From 7d87b9cd97a7d429dc3a3f4366407fd16b2a7595 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 12 Nov 2015 12:05:45 +0100 Subject: [PATCH 01/35] Timeline: Pass the right dragOffset to CategoryLabels Also, make sure the category dragger only reacts to vertical mouse movements. Change-Id: Ic53db9030536a1f2d35ea02facb920a4d3f0a005 Task-number: QTCREATORBUG-15333 Reviewed-by: Joerg Bornemann --- src/libs/timeline/qml/CategoryLabel.qml | 1 + src/libs/timeline/qml/TimelineLabels.qml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/timeline/qml/CategoryLabel.qml b/src/libs/timeline/qml/CategoryLabel.qml index 984d23519f5..a822ad835d2 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 ba3f883a420..c8eb63719bd 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); From 9db8adec7d07bc681624a4378d9d99718698e13b Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Mon, 16 Nov 2015 12:57:52 +0200 Subject: [PATCH 02/35] Export explicitly instantiate templates. LLVM & MSVC needs to explicitly export the instantiate templates. Change-Id: I51562750415400bfa561fd6e759211f2b4b10650 Reviewed-by: Erik Verbruggen --- src/libs/qmljs/qmljsinterpreter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index b7f2a915c25..098138eb6d2 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 >(const QString &, const QList &, const QString &); -template void CppQmlTypes::load< QHash >(const QString &, const QHash &, const QString &); +template QMLJS_EXPORT void CppQmlTypes::load< QList >(const QString &, const QList &, const QString &); +template QMLJS_EXPORT void CppQmlTypes::load< QHash >(const QString &, const QHash &, const QString &); QList CppQmlTypes::createObjectsForImport(const QString &package, ComponentVersion version) { From 611d7db4de7e415fa94a9e356628a3b20ec6a4a1 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 16 Nov 2015 15:40:15 +0100 Subject: [PATCH 03/35] Clang: Don't instantiate value two times Change-Id: I5619f157a8a251ad06f6ea63d310015d13eb4c9c Reviewed-by: Nikolai Kosjar --- src/tools/clangbackend/ipcsource/diagnostic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clangbackend/ipcsource/diagnostic.cpp b/src/tools/clangbackend/ipcsource/diagnostic.cpp index fdb7a0940a4..81e519894bd 100644 --- a/src/tools/clangbackend/ipcsource/diagnostic.cpp +++ b/src/tools/clangbackend/ipcsource/diagnostic.cpp @@ -113,7 +113,7 @@ std::vector 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; From bcd93b594eeac17ee5eebbf92a6ca78e7524674e Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 17 Nov 2015 13:33:31 +0100 Subject: [PATCH 04/35] Clang: Extract highlighting information Prepare the move of the semantic highlighting to the clang back end. We have it under tests too so it should be quite easy to make changes or corrections. Change-Id: I5706a8a06fde5a9ba2eba3a8ba62782102ac0bd3 Reviewed-by: Nikolai Kosjar --- .../clangbackendipc/clangbackendipc_global.h | 23 + src/libs/sqlite/utf8string.cpp | 5 + src/libs/sqlite/utf8string.h | 1 + .../ipcsource/clangbackendclangipc-source.pri | 15 +- .../clangbackend/ipcsource/clangstring.cpp | 7 +- .../clangbackend/ipcsource/clangstring.h | 2 + src/tools/clangbackend/ipcsource/cursor.cpp | 351 +++++++ src/tools/clangbackend/ipcsource/cursor.h | 129 +++ .../ipcsource/highlightinginformation.cpp | 304 ++++++ .../ipcsource/highlightinginformation.h | 86 ++ .../ipcsource/highlightinginformations.cpp | 79 ++ .../ipcsource/highlightinginformations.h | 74 ++ .../highlightinginformationsiterator.h | 99 ++ .../ipcsource/skippedsourceranges.cpp | 101 ++ .../ipcsource/skippedsourceranges.h | 63 ++ .../clangbackend/ipcsource/sourcelocation.cpp | 38 +- .../clangbackend/ipcsource/sourcelocation.h | 21 +- .../clangbackend/ipcsource/sourcerange.cpp | 30 + .../clangbackend/ipcsource/sourcerange.h | 11 +- .../ipcsource/translationunit.cpp | 54 +- .../clangbackend/ipcsource/translationunit.h | 18 + src/tools/clangbackend/ipcsource/type.cpp | 157 +++ src/tools/clangbackend/ipcsource/type.h | 87 ++ tests/unit/unittest/clangstringtest.cpp | 9 + tests/unit/unittest/cursortest.cpp | 819 ++++++++++++++++ tests/unit/unittest/data/cursor.cpp | 129 +++ tests/unit/unittest/data/cursor.h | 42 + .../data/highlightinginformations.cpp | 385 ++++++++ .../unittest/data/highlightinginformations.h | 0 .../unittest/data/skippedsourceranges.cpp | 19 + .../unittest/highlightinginformationstest.cpp | 902 ++++++++++++++++++ .../unit/unittest/skippedsourcerangestest.cpp | 159 +++ tests/unit/unittest/sourcelocationtest.cpp | 40 +- tests/unit/unittest/sourcerangetest.cpp | 47 +- tests/unit/unittest/unittest.pro | 5 +- 35 files changed, 4292 insertions(+), 19 deletions(-) create mode 100644 src/tools/clangbackend/ipcsource/cursor.cpp create mode 100644 src/tools/clangbackend/ipcsource/cursor.h create mode 100644 src/tools/clangbackend/ipcsource/highlightinginformation.cpp create mode 100644 src/tools/clangbackend/ipcsource/highlightinginformation.h create mode 100644 src/tools/clangbackend/ipcsource/highlightinginformations.cpp create mode 100644 src/tools/clangbackend/ipcsource/highlightinginformations.h create mode 100644 src/tools/clangbackend/ipcsource/highlightinginformationsiterator.h create mode 100644 src/tools/clangbackend/ipcsource/skippedsourceranges.cpp create mode 100644 src/tools/clangbackend/ipcsource/skippedsourceranges.h create mode 100644 src/tools/clangbackend/ipcsource/type.cpp create mode 100644 src/tools/clangbackend/ipcsource/type.h create mode 100644 tests/unit/unittest/cursortest.cpp create mode 100644 tests/unit/unittest/data/cursor.cpp create mode 100644 tests/unit/unittest/data/cursor.h create mode 100644 tests/unit/unittest/data/highlightinginformations.cpp create mode 100644 tests/unit/unittest/data/highlightinginformations.h create mode 100644 tests/unit/unittest/data/skippedsourceranges.cpp create mode 100644 tests/unit/unittest/highlightinginformationstest.cpp create mode 100644 tests/unit/unittest/skippedsourcerangestest.cpp diff --git a/src/libs/clangbackendipc/clangbackendipc_global.h b/src/libs/clangbackendipc/clangbackendipc_global.h index 544a5b15ac1..c9851069b58 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/sqlite/utf8string.cpp b/src/libs/sqlite/utf8string.cpp index b4492a9d198..c8cbaea2230 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 52c6f46758b..c6adfc93716 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/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri index 73aa363a959..93131082bf9 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 200e8342706..5decaf15490 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 f18a6122821..2db7b8ade0c 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 00000000000..7ea5009d4df --- /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 + +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 &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::outputArguments() const +{ + std::vector 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 00000000000..d4256401e5d --- /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 + +#include + +#include + +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 outputArguments() const; + + CXCursorKind kind() const; + + template + void visit(VisitorCallback visitorCallback) const; + +private: + CXCursor cxCursor; +}; + +template +void Cursor::visit(VisitorCallback visitorCallback) const +{ + auto visitor = [] (CXCursor cursor, CXCursor parent, CXClientData lambda) -> CXChildVisitResult { + auto &visitorCallback = *static_cast(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/highlightinginformation.cpp b/src/tools/clangbackend/ipcsource/highlightinginformation.cpp new file mode 100644 index 00000000000..808a0407d14 --- /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 +#include + +#include + +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::outputFunctionArguments() const +{ + QVector 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 00000000000..ee327b62135 --- /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 + +#include "cursor.h" + +#include + +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 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 00000000000..f7157768fd6 --- /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 00000000000..2c7b8ce9bbf --- /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 + +#include + +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; +}; + +} // 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 00000000000..53f540970e6 --- /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 +#include + +#include + +namespace ClangBackEnd { + +using uint = unsigned int; + +class DiagnosticSet; +class Diagnostic; + +class HighlightingInformationsIterator : public std::iterator +{ +public: + HighlightingInformationsIterator(std::vector::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::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 00000000000..2a39131474b --- /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 + +#include + +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 SkippedSourceRanges::sourceRanges() const +{ + std::vector sourceRanges; + + auto sourceRangeCount = cxSkippedSourceRanges->count; + sourceRanges.reserve(sourceRangeCount); + + std::copy(cxSkippedSourceRanges->ranges, + cxSkippedSourceRanges->ranges + sourceRangeCount, + std::back_inserter(sourceRanges)); + + return sourceRanges; +} + +QVector SkippedSourceRanges::toSourceRangeContainers() const +{ + QVector sourceRangeContainers; + + auto sourceRanges = this->sourceRanges(); + + std::copy(sourceRanges.cbegin(), + sourceRanges.cend(), + std::back_inserter(sourceRangeContainers)); + + return sourceRangeContainers; +} + +ClangBackEnd::SkippedSourceRanges::operator QVector() 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 00000000000..8d38bc50c9e --- /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 sourceRanges() const; + + QVector toSourceRangeContainers() const; + + operator QVector() 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 8a7cd0d8716..e04f44c7d88 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 @@ -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 3ee500623b8..83ba6c77c9c 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 7375988b2bd..f069edc9cb1 100644 --- a/src/tools/clangbackend/ipcsource/sourcerange.cpp +++ b/src/tools/clangbackend/ipcsource/sourcerange.cpp @@ -32,6 +32,8 @@ #include +#include + 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 3c80e4e040d..f9b786cf4aa 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 88e917010f6..8769f7caef3 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 e44852e4739..fd3831cb3e0 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 00000000000..a1f78e44eb2 --- /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 + +#include + +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 00000000000..099bfa4e3ee --- /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 + +#include + +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/tests/unit/unittest/clangstringtest.cpp b/tests/unit/unittest/clangstringtest.cpp index 0467de693df..b7ee1982b92 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 00000000000..e0e18c13083 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#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 00000000000..a492867dd6b --- /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 +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 00000000000..3e9e9a2bfb9 --- /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 00000000000..d651fd65e1c --- /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 +void TemplateFunction(T v) +{ + T XXXXX = v; +} +void TemplateReference() +{ + TemplateFunction(1); +// std::vector TemplateIntance; +} + + + + +template +class TemplateFoo {}; + + +template class TemplateTemplateParameter = TemplateFoo> +void TemplateFunction(TemplateTypeParameter TemplateParameter) +{ + TemplateTypeParameter TemplateTypeParameterReference; + auto NonTypeTemplateParameterReference = NonTypeTemplateParameter; + TemplateTemplateParameter TemplateTemplateParameterReference; +} + + + +void FinalClass::FinalClassThisCall() +{ + VirtualFunction(); +} + + +void OutputParameter(int &one, const int &two, int *three=0); + +void f12() +{ + int One; + OutputParameter(One, 2); +} + +#include + +#define FOREACH(variable, container) \ + variable; \ + auto x = container; + +#define foreach2 FOREACH + +#include + +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(&TypeInCast::function); + reinterpret_cast(&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 +void TemplateFunctionCall(Type type) +{ + type + type; +} + +void f16() +{ + TemplateFunctionCall(1); +} + + +template +class TemplatedType +{ + T value = T(); +}; + +void f17() +{ + TemplatedType TemplatedTypeDeclaration; +} diff --git a/tests/unit/unittest/data/highlightinginformations.h b/tests/unit/unittest/data/highlightinginformations.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit/unittest/data/skippedsourceranges.cpp b/tests/unit/unittest/data/skippedsourceranges.cpp new file mode 100644 index 00000000000..775393fcedc --- /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 00000000000..c09f12cc170 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#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 00000000000..b37b8726909 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#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 9db922c282b..9213d9359c3 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 771bd49ccff..b517c423804 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 193f1caa68e..6fe2d25f2e2 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 \ From 9f857880a714e63dd5bd53c4abd9444dc8d81d1e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 13 Nov 2015 17:55:33 +0100 Subject: [PATCH 05/35] QmlProfiler: Initialize the model progress numbers Change-Id: I037d0146e20d5fe1681f455fbd5da9ac5e89184b Reviewed-by: Joerg Bornemann --- src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index 0d1c6510df3..f4ac22cded0 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -149,6 +149,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; From 131c8027daa028e7daf6c525c8371fe590af668d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 13 Nov 2015 17:54:08 +0100 Subject: [PATCH 06/35] QmlProfiler: Fix traceTime updates If the trace time hasn't been set yet, decreaseStartTime and increaseEndTime should still do something. Change-Id: I626c0df66a5d7327708ada77c78546ad4aafc52b Reviewed-by: Joerg Bornemann --- src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index f4ac22cded0..d064f16b5b8 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -101,16 +101,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); } } From c37193f884c3a1989678c324d191d75cf905a383 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Tue, 17 Nov 2015 16:05:06 +0200 Subject: [PATCH 07/35] BareMetal: Fix cloning of GDB server providers Change-Id: Ie063ce3ab2caf5cf2ee709236db891e22bb9cc8b Reviewed-by: Denis Shienkov Reviewed-by: Tim Sander Reviewed-by: Tobias Hunger --- src/plugins/baremetal/gdbserverprovider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/baremetal/gdbserverprovider.cpp b/src/plugins/baremetal/gdbserverprovider.cpp index 5f32c7efbf2..cdb88987d45 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) From e072133aa419dfbfd9a55b57d346929abc3d5824 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 18 Nov 2015 13:11:16 +0100 Subject: [PATCH 08/35] Update qbs submodule. To HEAD of 1.4 branch. Change-Id: Ida2b0359866ce4397a8a10338103d592b0037d4f Reviewed-by: Joerg Bornemann --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index 94aaf3b94f9..ca3974a0828 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 94aaf3b94f9a9d8975349d75966917b4a8e0a439 +Subproject commit ca3974a0828c029e47f644931386fe6df200fbad From e39b515cd2659eb6ca1d50b515f1a8db46534bac Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 16 Nov 2015 12:30:25 +0100 Subject: [PATCH 09/35] GenericProject: Fix display of files in project directory Having a folder "." in the project tree is ugly, so fix that. Task-number: QTCREATORBUG-15344 Change-Id: I0817f609162dbc39f7bb4f98e6afe85169710fb7 Reviewed-by: Eike Ziller Reviewed-by: Tim Jenssen --- src/plugins/genericprojectmanager/genericprojectnodes.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/genericprojectmanager/genericprojectnodes.cpp b/src/plugins/genericprojectmanager/genericprojectnodes.cpp index b95f2d16a26..6afe039d02d 100644 --- a/src/plugins/genericprojectmanager/genericprojectnodes.cpp +++ b/src/plugins/genericprojectmanager/genericprojectnodes.cpp @@ -79,6 +79,9 @@ QHash sortFilesIntoPaths(const QString &base, const QSet Date: Wed, 18 Nov 2015 13:19:20 +0100 Subject: [PATCH 10/35] CustomWizard: Make sure to create wizards with unique ids only * Warn when somebody tries to register the same id twice * Make sure the user wizards override the global once so that this warning actually makes sense Change-Id: I69624666960c8836e25fd34abeef67015c1363ad Reviewed-by: Tim Jenssen --- .../customwizard/customwizard.cpp | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/plugins/projectexplorer/customwizard/customwizard.cpp b/src/plugins/projectexplorer/customwizard/customwizard.cpp index c52bd20eabf..fbbe9e7b9e9 100644 --- a/src/plugins/projectexplorer/customwizard/customwizard.cpp +++ b/src/plugins/projectexplorer/customwizard/customwizard.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -358,7 +359,6 @@ CustomWizard *CustomWizard::createWizard(const CustomProjectWizard::CustomWizard QList CustomWizard::createWizards() { - QList rc; QString errorMessage; QString verboseLog; const QString templateDirName = Core::ICore::resourcePath() + @@ -371,29 +371,32 @@ QList 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(); } 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 dirs = templateDir.entryInfoList(filters, sortflags); + QList 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 toCreate; + while (!dirs.isEmpty()) { const QFileInfo dirFi = dirs.takeFirst(); const QDir dir(dirFi.absoluteFilePath()); @@ -403,11 +406,13 @@ QList 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 CustomWizard::createWizards() } } } + + QList 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); From 10e947f65f19ec61e29afbaf167bf3439b5bea11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20H=C3=A4m=C3=A4l=C3=A4inen?= Date: Sun, 15 Nov 2015 00:16:34 +0200 Subject: [PATCH 11/35] C++: Fix crashes with the pattern "enum class operator A" Parser parsed the pattern as an enum declaration the name of which is a conversion operator. Add check to disallow keywords after enum-key (enum, enum class, enum struct). Add tests tst_AST::enumDeclaration and invalidEnumClassDeclaration. Task-number: QTCREATORBUG-15341 Change-Id: Ia037f00184c1d7e5b0374f39331bb6748f8d90b1 Reviewed-by: Nikolai Kosjar --- src/libs/3rdparty/cplusplus/Parser.cpp | 5 +++++ tests/auto/cplusplus/ast/tst_ast.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 6fccebb0155..901f5ac2c1f 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/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp index a2219e7cfc6..aa42b2b3ec2 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 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 unit(parseStatement( + "enum class operator A { };", true)); + + QVERIFY(diag.errorCount != 0); +} + void tst_AST::initTestCase() { control.setDiagnosticClient(&diag); From 82cf0e60fbf4d49987b9e51bf0c1813f61ba1d02 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Tue, 17 Nov 2015 16:25:02 +0100 Subject: [PATCH 12/35] Clang: Fix include paths for MSVC toolchains Prevent libclang from using any builtin includes paths or any standard system directories. The project manager provides us all the necessary information. Task-number: QTCREATORBUG-15345 Change-Id: I70e2dafea8d049a9b7a32b24ce2d4ce3dac2cd3b Reviewed-by: Marco Bubke --- src/plugins/clangcodemodel/clangutils.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index fd9064a3f56..28c223d80ad 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -41,6 +41,8 @@ #include #include +#include + #include #include @@ -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()) { From d6284c58634f3d6f2e8a13c037fcb477f8654396 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 19 Nov 2015 10:25:35 +0100 Subject: [PATCH 13/35] Doc: changing file encoding from editor toolbar Change-Id: I0931f1f4cd9641662fdaf5e67943e6b85c19c1c0 Reviewed-by: Eike Ziller --- doc/src/editors/creator-coding-edit-mode.qdoc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/src/editors/creator-coding-edit-mode.qdoc b/doc/src/editors/creator-coding-edit-mode.qdoc index f80aec704d5..4693ae1ac43 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} From c2a2883c4a982e52947e73ca97ba646fda54e6e2 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 19 Nov 2015 12:56:17 +0100 Subject: [PATCH 14/35] Doc: move the "Modeling" section to end of "Coding" Because the model editor does not generate code from the diagrams and is therefore mainly meant for documenting code. Change-Id: I43d2dd3436df4914f5be6f8b2f52586de1522138 Reviewed-by: Eike Ziller --- doc/src/editors/creator-coding.qdoc | 2 +- doc/src/editors/creator-editors-writing-code.qdoc | 2 +- doc/src/editors/creator-mime-types.qdoc | 2 +- doc/src/editors/creator-modeling.qdoc | 4 ++-- doc/src/projects/creator-projects-building-running.qdoc | 2 +- doc/src/qtcreator.qdoc | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/src/editors/creator-coding.qdoc b/doc/src/editors/creator-coding.qdoc index 49e64809821..3cb58bf3c2d 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 diff --git a/doc/src/editors/creator-editors-writing-code.qdoc b/doc/src/editors/creator-editors-writing-code.qdoc index d30e89716af..8ee82d22295 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 diff --git a/doc/src/editors/creator-mime-types.qdoc b/doc/src/editors/creator-mime-types.qdoc index e1f7544a4c7..c2f8fff8bab 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 77f9681a24d..36200a11d15 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/projects/creator-projects-building-running.qdoc b/doc/src/projects/creator-projects-building-running.qdoc index 047c4764d1a..0159b79da32 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 7f33c68dc57..867d29c231c 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 @@ -194,7 +194,6 @@ \endlist \li \l{Coding} \list - \li \l{Modeling} \li \l{Writing Code} \list \li \l{Working in Edit Mode} @@ -221,6 +220,7 @@ \li \l{Using FakeVim Mode} \endlist \li \l{Editing MIME Types} + \li \l{Modeling} \endlist \li \l{Building and Running} \list From 0498fb68ff76adc39c8744ff354d5dcc5ab94da8 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 19 Nov 2015 13:49:26 +0100 Subject: [PATCH 15/35] C++: Revert lookup to 3.4.2 ...which was least buggy. The bugs fixed by the changes we revert here (highlighting/completion for code involving templates) were minor compared to ones we currently have. Those bugs will be addressed by the clang code model anyway. Relevant commits were collected via: $ cd ${QTC}/src/libs/cplusplus $ git log \ --no-merges \ --format=oneline \ v3.4.2..HEAD \ -- LookupContext.* ResolveExpression.* TypeResolver.* TypeOfExpression.* \ ../../plugins/cpptools/cppcompletion_test.cpp From this list the following were skipped due to irrelevance: 88c5b47e535d91f3db99882d5b50b263b46f223c # CppTools: Minor cleanup in completion tests e5255a1f5cac284c4f0d4a85203878c84da86e85 # CppTools: Add a test for ObjC not replacing dot with arrow 5b12c8d63a30e281274cdc267efabead2c736bd8 # CppTools: Support ObjC in member access operator tests 9fef4fb9ca4e65e20ff13b98bcf15e3c6232fdfb # CPlusPlus: Fix warnings about overriding visit(...) methods There were only minor conflicts while reverting those. This changes touches so many files because there were quite some cleanups and renames after the 3.4.2 release. Task-number: QTCREATORBUG-14889 Task-number: QTCREATORBUG-15211 Task-number: QTCREATORBUG-15213 Task-number: QTCREATORBUG-15257 Task-number: QTCREATORBUG-15264 Task-number: QTCREATORBUG-15291 Task-number: QTCREATORBUG-15329 Change-Id: I01f759f8f35ecb4228928a4f22086e279c1a5435 Reviewed-by: Marco Bubke --- src/libs/3rdparty/cplusplus/AST.h | 2 +- src/libs/3rdparty/cplusplus/Bind.cpp | 40 +- .../cplusplus/CPlusPlusForwardDeclarations.h | 1 - src/libs/3rdparty/cplusplus/Control.cpp | 16 +- src/libs/3rdparty/cplusplus/Control.h | 3 - .../3rdparty/cplusplus/FullySpecifiedType.cpp | 6 - .../3rdparty/cplusplus/FullySpecifiedType.h | 4 - src/libs/3rdparty/cplusplus/Matcher.cpp | 11 - src/libs/3rdparty/cplusplus/Matcher.h | 1 - src/libs/3rdparty/cplusplus/Names.h | 2 +- src/libs/3rdparty/cplusplus/Scope.cpp | 2 +- src/libs/3rdparty/cplusplus/Symbol.cpp | 3 - src/libs/3rdparty/cplusplus/Symbol.h | 7 +- src/libs/3rdparty/cplusplus/SymbolVisitor.h | 1 - src/libs/3rdparty/cplusplus/Symbols.cpp | 52 - src/libs/3rdparty/cplusplus/Symbols.h | 33 - src/libs/3rdparty/cplusplus/Templates.cpp | 20 +- src/libs/3rdparty/cplusplus/Templates.h | 2 - src/libs/3rdparty/cplusplus/Type.cpp | 3 - src/libs/3rdparty/cplusplus/Type.h | 3 - src/libs/3rdparty/cplusplus/TypeVisitor.h | 1 - src/libs/cplusplus/CppRewriter.cpp | 2 +- src/libs/cplusplus/CppRewriter.h | 4 +- .../DeprecatedGenTemplateInstance.cpp | 430 +++++ ...lver.h => DeprecatedGenTemplateInstance.h} | 45 +- src/libs/cplusplus/FindUsages.cpp | 2 +- src/libs/cplusplus/LookupContext.cpp | 1377 ++++++++--------- src/libs/cplusplus/LookupContext.h | 209 ++- src/libs/cplusplus/LookupItem.cpp | 4 +- src/libs/cplusplus/LookupItem.h | 8 +- src/libs/cplusplus/ResolveExpression.cpp | 415 ++++- src/libs/cplusplus/ResolveExpression.h | 15 +- src/libs/cplusplus/TypeOfExpression.cpp | 8 +- src/libs/cplusplus/TypeOfExpression.h | 14 +- src/libs/cplusplus/TypeResolver.cpp | 262 ---- src/libs/cplusplus/cplusplus-lib.pri | 4 +- src/libs/cplusplus/cplusplus.qbs | 2 +- src/libs/qmljs/qmljsfindexportedcpptypes.cpp | 2 +- src/plugins/cppeditor/cppeditor.cpp | 2 +- src/plugins/cppeditor/cppelementevaluator.cpp | 12 +- .../cppeditor/cppfollowsymbolundercursor.cpp | 3 +- .../cppeditor/cppfunctiondecldeflink.cpp | 4 +- .../cppeditor/cppinsertvirtualmethods.cpp | 16 +- src/plugins/cppeditor/cppquickfixes.cpp | 24 +- .../cppvirtualfunctionassistprovider.cpp | 4 +- .../followsymbol_switchmethoddecldef_test.cpp | 16 +- src/plugins/cpptools/cppchecksymbols.cpp | 30 +- src/plugins/cpptools/cppchecksymbols.h | 6 +- src/plugins/cpptools/cppcompletion_test.cpp | 520 +------ src/plugins/cpptools/cppcompletionassist.cpp | 76 +- src/plugins/cpptools/cppcompletionassist.h | 8 +- src/plugins/cpptools/cpptoolsreuse.cpp | 2 +- src/plugins/cpptools/symbolfinder.cpp | 16 +- src/plugins/cpptools/symbolfinder.h | 3 +- .../cplusplus-mkvisitor.cpp | 50 +- .../checksymbols/tst_checksymbols.cpp | 143 +- tests/auto/cplusplus/lookup/tst_lookup.cpp | 6 +- .../auto/cplusplus/semantic/tst_semantic.cpp | 31 +- 58 files changed, 1800 insertions(+), 2188 deletions(-) create mode 100644 src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp rename src/libs/cplusplus/{TypeResolver.h => DeprecatedGenTemplateInstance.h} (57%) delete mode 100644 src/libs/cplusplus/TypeResolver.cpp diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 8c3ceca968f..bcdf0433627 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 0deb19dd544..63940d19ddc 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 **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 54f9db96dac..9b1c5a30cf7 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 463a2f88f69..afdd6790560 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 bb2bf9cd108..85b8c3d3d7c 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 ea88140314d..f78e4e9338e 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 4c7a21ddc35..8f200184659 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 379ed595869..7a3c21cafc9 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 4d2b40b64d1..1a9d9d35116 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 7b49190f8ec..33f40d523d5 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/Scope.cpp b/src/libs/3rdparty/cplusplus/Scope.cpp index 783eff77ae3..406a794c7e0 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 0ddd4ffbb2a..ae20b14bb75 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 cbed45f4612..919268b14b6 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 5331525e9fa..4311672eca8 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 3c632f1cd7f..f8a8440c097 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(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 f2d92c23f2b..257bdb86826 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 41e462a3b87..3b8ae9a23f6 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 e39f79a7a66..9db69084f71 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 69ffb5030a8..bad4d42eebd 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 2661628f76a..958ba15efdd 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 86568dcebca..b3a24b15723 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/cplusplus/CppRewriter.cpp b/src/libs/cplusplus/CppRewriter.cpp index fa66e3b4e31..63eadd912c5 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 cb307a9401a..cc68f662a5b 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 00000000000..e037f87c58f --- /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 +#include +#include +#include +#include +#include + +#include +#include + +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 _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 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 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 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, 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) +{ + 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 similarity index 57% rename from src/libs/cplusplus/TypeResolver.h rename to src/libs/cplusplus/DeprecatedGenTemplateInstance.h index bf25e468c6a..9e488478c6e 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 +#include +#include + +#include +#include +#include namespace CPlusPlus { -class TypeResolver +class CPLUSPLUS_EXPORT DeprecatedGenTemplateInstance { public: - TypeResolver(CreateBindings &factory) : _factory(factory) {} - void resolve(FullySpecifiedType *type, Scope **scope, LookupScope *binding); - static QList resolveDeclInitializer( - CreateBindings &factory, const Declaration *decl, - const QSet &declarationsBeingResolved, - const Identifier *id = 0); + typedef QList< QPair > Substitution; + +public: + static FullySpecifiedType instantiate(const Name *className, Symbol *candidate, QSharedPointer control); private: - NamedType *getNamedType(FullySpecifiedType& type) const; + DeprecatedGenTemplateInstance(QSharedPointer control, const Substitution &substitution); + FullySpecifiedType gen(Symbol *symbol); - QList getNamedTypeItems(const Name *name, Scope *scope, - LookupScope *binding) const; - - static QList typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope); - - static bool isTypedefWithName(const Declaration *declaration, const Name *name); - - bool findTypedef(const QList& namedTypeItems, FullySpecifiedType *type, - Scope **scope, QSet& visited); - - CreateBindings &_factory; - // binding has to be remembered in case of resolving typedefs for templates - LookupScope *_binding; +private: + QSharedPointer _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 b9d34bd00c3..0640fab537f 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 401d54f48b3..be1968733eb 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 #include @@ -41,19 +41,16 @@ #include #include #include -#include #include #include #include #include +using namespace CPlusPlus; + static const bool debug = ! qgetenv("QTC_LOOKUPCONTEXT_DEBUG").isEmpty(); -namespace CPlusPlus { - -typedef QSet ProcessedSet; - static void addNames(const Name *name, QList *names, bool addAllNames = false) { if (! name) @@ -92,6 +89,24 @@ static void path_helper(Symbol *symbol, QList *names) } } +static bool isNestedInstantiationEnclosingTemplate( + ClassOrNamespace *nestedClassOrNamespaceInstantiation, + ClassOrNamespace *enclosingTemplateClassInstantiation) +{ + QList 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 &path, const QList 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 names = LookupContext::fullyQualifiedName(symbol); @@ -241,7 +260,7 @@ const Name *LookupContext::minimalName(Symbol *symbol, LookupScope *target, Cont } QList LookupContext::lookupByUsing(const Name *name, - LookupScope *bindingScope) const + ClassOrNamespace *bindingScope) const { QList candidates; // if it is a nameId there can be a using declaration for it @@ -275,7 +294,7 @@ QList 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 typedefsBeingResolved) const +ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope, + ClassOrNamespace *enclosingBinding, + QSet 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 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 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 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 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 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 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 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 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 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 LookupContext::lookup(const Name *name, Scope *scope) const return candidates; } -LookupScope *LookupContext::lookupParent(Symbol *symbol) const +ClassOrNamespace *LookupContext::lookupParent(Symbol *symbol) const { QList 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 Table; - typedef std::map TypedefTable; - typedef std::map TemplateNameIdTable; - typedef QHash Anonymouses; - - LookupScopePrivate *allocateChild(const Name *name); - - void flush(); - - LookupScope *globalNamespace() const; - - Symbol *lookupInScope(const QList &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 lookup_helper(const Name *name, bool searchInEnclosingScope); - - void lookup_helper(const Name *name, LookupScopePrivate *binding, - QList *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 _symbols; - QList _usings; - Table _nestedScopes; - TypedefTable _typedefs; - QHash _blocks; - QList _enums; - QList _todo; - QSharedPointer _control; - TemplateNameIdTable _specializations; - QMap _instantiations; - Anonymouses _anonymouses; - QSet _declaredOrTypedefedAnonymouses; - - QHash *_scopeLookupCache; - - // it's an instantiation. - LookupScopePrivate *_instantiationOrigin; - - AlreadyConsideredClassContainer _alreadyConsideredClasses; - AlreadyConsideredClassContainer _alreadyConsideredTemplates; - QSet _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::usings() const { - if (Internal::LookupScopePrivate *i = d->_instantiationOrigin) - return i->q; - return 0; + const_cast(this)->flush(); + return _usings; } -LookupScope *LookupScope::parent() const +QList ClassOrNamespace::unscopedEnums() const { - if (Internal::LookupScopePrivate *p = d->_parent) - return p->q; - return 0; + const_cast(this)->flush(); + return _enums; } -QList LookupScope::usings() const +QList ClassOrNamespace::symbols() const { - const_cast(this)->d->flush(); - return d->_usings; + const_cast(this)->flush(); + return _symbols; } -QList LookupScope::unscopedEnums() const +ClassOrNamespace *ClassOrNamespace::globalNamespace() const { - const_cast(this)->d->flush(); - return d->_enums; -} - -QList LookupScope::symbols() const -{ - const_cast(this)->d->flush(); - return d->_symbols; -} - -QList LookupScope::find(const Name *name) -{ - return d->lookup_helper(name, false); -} - -QList 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(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 LookupScopePrivate::lookup_helper(const Name *name, bool searchInEnclosingScope) +QList ClassOrNamespace::find(const Name *name) +{ + return lookup_helper(name, false); +} + +QList ClassOrNamespace::lookup(const Name *name) +{ + return lookup_helper(name, true); +} + +QList ClassOrNamespace::lookup_helper(const Name *name, bool searchInEnclosingScope) { QList 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 fullName; addNames(name, &fullName); @@ -735,10 +631,10 @@ QList 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 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 LookupScopePrivate::lookup_helper(const Name *name, bool searc return result; } - ProcessedSet processed; - ProcessedSet processedOwnParents; - LookupScopePrivate *binding = this; + QSet processed; + QSet 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 LookupScopePrivate::lookup_helper(const Name *name, bool searc return result; } -void LookupScopePrivate::lookup_helper( - const Name *name, LookupScopePrivate *binding, QList *result, - ProcessedSet *processed) +void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding, + QList *result, + QSet *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->unscopedEnums()) + _factory->lookupInScope(name, e, result, templateId, binding); + + 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(); + ClassOrNamespace *a = cit.value(); + if (!binding->_declaredOrTypedefedAnonymouses.contains(anonymousNameId)) + lookup_helper(name, a, result, processed, binding->_templateId); } } - - foreach (Enum *e, binding->_enums) - _factory->lookupInScope(name, e, result, binding->q); - - foreach (LookupScope *u, binding->_usings) - lookup_helper(name, u->d, 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(); - LookupScopePrivate *a = cit.value(); - if (!binding->_declaredOrTypedefedAnonymouses.contains(anonymousNameId)) - lookup_helper(name, a, result, processed); - } -} - } void CreateBindings::lookupInScope(const Name *name, Scope *scope, QList *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("")); + << (binding ? oo(binding->_name) : QString::fromLatin1("")); } 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 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::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::const_iterator citBlock = _blocks.constFind(block); + if (citBlock != _blocks.constEnd()) { + ClassOrNamespace *nestedBlock = citBlock.value(); + QSet 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 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 *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 processed; + return findBlock_helper(block, &processed, true); } -Symbol *Internal::LookupScopePrivate::lookupInScope(const QList &fullName) +Symbol *ClassOrNamespace::lookupInScope(const QList &fullName) { if (!_scopeLookupCache) { _scopeLookupCache = new QHash; - 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 &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 *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 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)) { + 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(); + } + } + + foreach (ClassOrNamespace *u, usings()) { + if (ClassOrNamespace *r = u->lookupType_helper(name, + processed, + /*searchInEnclosingScope =*/ false, + origin)) return r; - } - } - - if (_instantiationOrigin) { - if (LookupScope *o = _instantiationOrigin->lookupType_helper( - name, processed, /*searchInEnclosingScope =*/ true, origin)) { - return o; - } } } @@ -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_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(this)->flush(); + const_cast(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_iterator citInstantiation + = reference->_instantiations.constFind(templId); if (citInstantiation != reference->_instantiations.constEnd()) return citInstantiation.value(); TemplateNameId *nonConstTemplId = const_cast(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 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 knownUsings = reference->_usings.toSet(); + QSet 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); + // The instantiation should have all symbols, enums, and usings from the reference. + instantiation->_enums.append(reference->unscopedEnums()); + instantiation->_usings.append(reference->usings()); - QHash templParams; - for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) - templParams.insert(templateSpecialization->templateParameterAt(i)->name(), i); + instantiation->_rootClass = reference->rootClass(); - foreach (const Name *baseName, allBases) { - LookupScope *baseBinding = 0; + // 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(); - if (const Identifier *nameId = baseName->asNameId()) { - // This is the simple case in which a template parameter is itself a base. - // Ex.: template 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()); + 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 TypenameArgument *tParam + = templateSpecialization->templateParameterAt(i)->asTypenameArgument(); + if (!tParam) + continue; + const Name *name = tParam->name(); + if (!name) + continue; + + FullySpecifiedType ty = (i < argumentCountOfInitialization) ? + templId->templateArgumentAt(i): + cloner.type(tParam->type(), &subst); + + if (i < templSpecArgumentCount + && templSpecId->templateArgumentAt(i)->isPointerType()) { + if (PointerType *pointerType = ty->asPointerType()) + ty = pointerType->elementType(); + } + + subst.bind(cloner.name(name, &subst), ty); + } + + 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()); + } + } } } } - if (!baseBinding && subst.contains(baseName)) { - const FullySpecifiedType &fullType = subst[baseName]; - if (fullType.isValid()) { - if (NamedType *namedType = fullType.type()->asNamedType()) - baseBinding = q->lookupType(namedType->name()); - } - } + instantiateNestedClasses(reference, cloner, subst, instantiation); } 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 A : public B {}; - if (baseTemplId->identifier() != templId->identifier()) { - if (LookupScopePrivate *nested = nestedType(baseName, origin)) - baseBinding = nested->q; - } - } else if (const QualifiedNameId *qBaseName = baseName->asQualifiedNameId()) { - // Qualified names in general. - // Ex.: template class A : public B::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); - } - baseName = qBaseName->name(); - - if (binding) - baseBinding = binding->lookupType(baseName); - } + instantiation->_symbols.append(reference->symbols()); } - if (baseBinding && !knownUsings.contains(baseBinding)) - instantiation->addUsing(baseBinding); + QHash 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 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()); + } + } + } + if (!baseBinding && subst.contains(baseName)) { + const FullySpecifiedType &fullType = subst[baseName]; + if (fullType.isValid()) { + if (NamedType *namedType = fullType.type()->asNamedType()) + baseBinding = lookupType(namedType->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 A : public B {}; + if (baseTemplId->identifier() != templId->identifier()) + baseBinding = nestedType(baseName, origin); + } else if (const QualifiedNameId *qBaseName = baseName->asQualifiedNameId()) { + // Qualified names in general. + // Ex.: template class A : public B::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 (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::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 &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; } -void LookupScopePrivate::flush() +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 +} + +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 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(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 path = LookupContext::path(symbol); return lookupType(path, enclosingBinding); } -LookupScope *CreateBindings::lookupType(const QList &path, - LookupScope *enclosingBinding) +ClassOrNamespace *CreateBindings::lookupType(const QList &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 &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); + // does this block contain any other blocks or classOrNamespaces + process(block->memberAt(i), _currentClassOrNamespace); - // 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; + // 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 8410c9000b7..5858d80c954 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -41,7 +41,6 @@ #include #include -#include #include #include @@ -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 usings() const; + ClassOrNamespace *parent() const; + QList usings() const; QList unscopedEnums() const; QList symbols() const; + ClassOrNamespace *globalNamespace() const; + QList lookup(const Name *name); QList 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); - /// The class this LookupScope is based on. - Class *rootClass() const; + Symbol *lookupInScope(const QList &fullName); + + /// The class this ClassOrNamespace is based on. + Class *rootClass() const { return _rootClass; } private: - Internal::LookupScopePrivate *d; + typedef std::map Table; + typedef std::map TemplateNameIdTable; + typedef QHash 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 lookup_helper(const Name *name, bool searchInEnclosingScope); + + void lookup_helper(const Name *name, ClassOrNamespace *binding, + QList *result, + QSet *processed, + const TemplateNameId *templateId); + + ClassOrNamespace *lookupType_helper(const Name *name, QSet *processed, + bool searchInEnclosingScope, ClassOrNamespace *origin); + + ClassOrNamespace *findBlock_helper(Block *block, QSet *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 _symbols; + QList _usings; + Table _classOrNamespaces; + QHash _blocks; + QList _enums; + QList _todo; + QSharedPointer _control; + TemplateNameIdTable _specializations; + QMap _instantiations; + Anonymouses _anonymouses; + QSet _declaredOrTypedefedAnonymouses; + + QHash *_scopeLookupCache; + + // it's an instantiation. + const TemplateNameId *_templateId; + ClassOrNamespace *_instantiationOrigin; + + AlreadyConsideredClassContainer _alreadyConsideredClasses; + AlreadyConsideredClassContainer _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 &symbols) const; + bool containsTemplateType(Declaration *declaration) const; + bool containsTemplateType(Function *function) const; + NamedType *findNamedType(Type *memberType) const; + + QSet _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 +class CPLUSPLUS_EXPORT CreateBindings: protected SymbolVisitor { Q_DISABLE_COPY(CreateBindings) public: - typedef QSharedPointer 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 &path, LookupScope *enclosingBinding = 0); + ClassOrNamespace *lookupType(Symbol *symbol, ClassOrNamespace *enclosingBinding = 0); + ClassOrNamespace *lookupType(const QList &path, + ClassOrNamespace *enclosingBinding = 0); /// Returns the Control that must be used to create temporary symbols. /// \internal QSharedPointer 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 *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; - QList _expressionDocuments; QSet _processed; - QList _entities; - LookupScope *_globalNamespace; - LookupScope *_currentLookupScope; + QList _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 bindings = QSharedPointer()); 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 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 typedefsBeingResolved = QSet()) 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 bindings() const { return _bindings; } static QList fullyQualifiedName(Symbol *symbol); static QList 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 lookupByUsing(const Name *name, LookupScope *bindingScope) const; + QList 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 _bindings; bool m_expandTemplates; }; diff --git a/src/libs/cplusplus/LookupItem.cpp b/src/libs/cplusplus/LookupItem.cpp index 4e22389503d..0621c1f6e92 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 13963b70643..46c7b34716b 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 43887b2995c..adaac12ab5f 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 #include @@ -75,6 +75,131 @@ static QList removeDuplicates(const QList &results) return uniqueList; } +class TypedefsResolver +{ +public: + TypedefsResolver(const LookupContext &context) : _context(context) {} + void resolve(FullySpecifiedType *type, Scope **scope, ClassOrNamespace *binding) + { + QSet 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 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 getNamedTypeItems(const Name *name, Scope *scope, + ClassOrNamespace *binding) const + { + QList 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 typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope) + { + QList 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& namedTypeItems, FullySpecifiedType *type, + Scope **scope, QSet& 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 &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 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(_autoDeclarationsBeingResolved) << decl); + + Document::Ptr exprDoc = + documentForExpression(exprTyper.preprocessedExpression(initializer)); + exprDoc->check(); + + DeduceAutoCheck deduceAuto(ast->name->identifier(), exprDoc->translationUnit()); + if (deduceAuto._block) + continue; + + const QList &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 ResolveExpression::getMembers(LookupScope *binding, const Name *memberName) const +QList 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 &baseResults, - int accessOp, - bool *replacedDotOperator) const +ClassOrNamespace *ResolveExpression::baseExpression(const QList &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 &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); + } - typeResolver.resolve(&ty, &scope, r.binding()); + typedefsResolver.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-> + } else { + ClassOrNamespace *binding + = findClassForTemplateParameterInExpressionScope(r.binding(), + ty); - 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 (! binding) + binding = findClass(ty, scope, r.binding()); - if (Function *funTy = overload->type()->asFunctionType()) { - FullySpecifiedType retTy = funTy->returnType().simplified(); + if (binding){ + // lookup for overloads of operator-> - typeResolver.resolve(&retTy, &functionScope, r.binding()); - - 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 (PointerType *ptrTy = retTy->asPointerType()) - retTy = ptrTy->elementType(); + if (overload->type()->isFunctionType()) { + FullySpecifiedType overloadTy + = instantiate(binding->templateId(), overload); + Function *instantiatedFunction = overloadTy->asFunctionType(); + Q_ASSERT(instantiatedFunction != 0); - if (LookupScope *retBinding = findClass(retTy, functionScope)) - return retBinding; + FullySpecifiedType retTy + = instantiatedFunction->returnType().simplified(); - if (scope != functionScope) { - if (LookupScope *retBinding = findClass(retTy, scope)) + typedefsResolver.resolve(&retTy, &functionScope, r.binding()); + + if (! retTy->isPointerType() && ! retTy->isNamedType()) + continue; + + if (PointerType *ptrTy = retTy->asPointerType()) + retTy = ptrTy->elementType(); + + 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 &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 &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 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 df9ea220205..aee53c40fae 100644 --- a/src/libs/cplusplus/ResolveExpression.h +++ b/src/libs/cplusplus/ResolveExpression.h @@ -53,25 +53,26 @@ public: QList resolve(ExpressionAST *ast, Scope *scope, bool ref = false); QList reference(ExpressionAST *ast, Scope *scope); - LookupScope *baseExpression(const QList &baseResults, + ClassOrNamespace *baseExpression(const QList &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 expression(ExpressionAST *ast); QList switchResults(const QList &symbols); + FullySpecifiedType instantiate(const Name *className, Symbol *candidate) const; - QList getMembers(LookupScope *binding, const Name *memberName) const; + QList 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 &symbols); void addResults(const QList &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 bc0792262a4..8d5be1b2519 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 bindings, const QSet &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(new CreateBindings(thisDocument, snapshot)); m_environment.clear(); m_autoDeclarationsBeingResolved = autoDeclarationsBeingResolved; @@ -105,7 +105,7 @@ QList 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 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 0308f9a45ee..158b3e9815e 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 bindings = QSharedPointer(), const QSet &autoDeclarationsBeingResolved = QSet()); @@ -135,6 +135,7 @@ public: } private: + void processEnvironment(Document::Ptr doc, Environment *env, QSet *processed) const; @@ -142,13 +143,20 @@ private: private: Document::Ptr m_thisDocument; Snapshot m_snapshot; - CreateBindings::Ptr m_bindings; + QSharedPointer m_bindings; ExpressionAST *m_ast; Scope *m_scope; LookupContext m_lookupContext; mutable QSharedPointer m_environment; - QSet 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 m_documents; + + QSet 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 1be33f1410d..00000000000 --- 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 - -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 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 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 TypeResolver::getNamedTypeItems(const Name *name, Scope *scope, - LookupScope *binding) const -{ - QList 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 TypeResolver::typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope) -{ - QList 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 TypeResolver::resolveDeclInitializer( - CreateBindings &factory, const Declaration *decl, - const QSet &declarationsBeingResolved, - const Identifier *id) -{ - const StringLiteral *initializationString = decl->getInitializer(); - if (initializationString == 0) - return QList(); - - const QByteArray &initializer = - QByteArray::fromRawData(initializationString->chars(), - initializationString->size()).trimmed(); - - // Skip lambda-function initializers - if (initializer.length() > 0 && initializer[0] == '[') - return QList(); - - 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(); - } - - 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 &namedTypeItems, FullySpecifiedType *type, - Scope **scope, QSet &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 resolved = - resolveDeclInitializer(_factory, decl, QSet() << 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 ebb5ad07f1e..0e5bed22e08 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 8ac08217eb4..dd4012d633d 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 f7edb410d24..cf1dde0819c 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/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 81c7dc71581..2abdef298ba 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 declarations = context.lookup(functionDefinitionSymbol->name(), functionDefinitionSymbol->enclosingScope()); diff --git a/src/plugins/cppeditor/cppelementevaluator.cpp b/src/plugins/cppeditor/cppelementevaluator.cpp index 97b25d723f7..6740b935cc2 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 Data; + typedef QPair Data; - if (LookupScope *clazz = context.lookupType(declaration)) { - QSet visited; + if (ClassOrNamespace *clazz = context.lookupType(declaration)) { + QSet visited; QQueue 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 &bases = clazz->usings(); - foreach (LookupScope *baseClass, bases) { + const QList &bases = clazz->usings(); + foreach (ClassOrNamespace *baseClass, bases) { const QList &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 a166e8d6412..407252ca507 100644 --- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -184,7 +183,7 @@ Class *VirtualFunctionHelper::staticClassOfFunctionCallExpression_internal() con const QList 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 dfb0b1018a7..4c359ed9b62 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 ab6d15ead4a..222d8a90fff 100644 --- a/src/plugins/cppeditor/cppinsertvirtualmethods.cpp +++ b/src/plugins/cppeditor/cppinsertvirtualmethods.cpp @@ -566,15 +566,15 @@ public: // Determine base classes QList baseClasses; - QQueue baseClassQueue; - QSet visitedBaseClasses; - if (LookupScope *clazz = interface.context().lookupType(m_classAST->symbol)) + QQueue baseClassQueue; + QSet 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 bases = clazz->usings(); - foreach (LookupScope *baseClass, bases) { + const QList bases = clazz->usings(); + foreach (ClassOrNamespace *baseClass, bases) { foreach (Symbol *symbol, baseClass->symbols()) { Class *base = symbol->asClass(); if (base @@ -768,7 +768,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); @@ -865,7 +865,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 176afcb7f9b..9ef84adad2d 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 &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 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 61828f1631d..3b4ba8baf50 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 956b02b5d98..fbcda2628e4 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\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 struct A { virtual void virt() {} };\n" "void f(A *l) { l->$@virt(); }\n") << (OverrideItemList() - << OverrideItem(QLatin1String("A::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 acf3d5c86f6..cbc6baf75e8 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 processed; - QList todo; + QSet processed; + QList 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 &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 11cde211460..f874c163231 100644 --- a/src/plugins/cpptools/cppchecksymbols.h +++ b/src/plugins/cpptools/cppchecksymbols.h @@ -105,7 +105,7 @@ protected: const QList &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 &candidates, CPlusPlus::NameAST *ast); diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 02cc06848f6..7deb309f587 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\n" - "struct Foo { T bar; };\n" - "\n" - "template class Foo;\n" - "\n" - "void func()\n" - "{\n" - " Foo 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,29 +1311,22 @@ void CppToolsPlugin::test_completion_data() << QLatin1String("Template1")); QTest::newRow("template_specialization_with_pointer") << _( - "template struct Temp { T variable; };\n" - "template struct Temp { T *pointer; };\n" - "void func()\n" + "template \n" + "struct Template\n" "{\n" - " Temp templ;\n" - " @\n" - "}" + " T variable;\n" + "};\n" + "template \n" + "struct Template\n" + "{\n" + " T *pointer;\n" + "};\n" + "Template templ;\n" + "@\n" ) << _("templ.") << (QStringList() - << QLatin1String("Temp") + << QLatin1String("Template") << QLatin1String("pointer")); - QTest::newRow("template_specialization_with_reference") << _( - "template struct Temp { T variable; };\n" - "template struct Temp { T reference; };\n" - "void func()\n" - "{\n" - " Temp templ;\n" - " @\n" - "}" - ) << _("templ.") << (QStringList() - << QLatin1String("Temp") - << QLatin1String("reference")); - QTest::newRow("typedef_using_templates1") << _( "namespace NS1\n" "{\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 \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 \n" @@ -2689,78 +2628,6 @@ void CppToolsPlugin::test_completion_data() ) << _("s.") << (QStringList() << QLatin1String("S")); - QTest::newRow("partial_specialization") << _( - "struct b {};\n" - "template struct s { float f; };\n" - "template struct s { int i; };\n" - "\n" - "void f()\n" - "{\n" - " s var;\n" - " @\n" - "}\n" - ) << _("var.") << (QStringList() - << QLatin1String("i") - << QLatin1String("s")); - -// QTest::newRow("partial_specialization_with_pointer") << _( -// "struct b {};\n" -// "struct a : b {};\n" -// "template struct s { float f; };\n" -// "template struct s { int i; };\n" -// "template struct s { char j; };\n" -// "\n" -// "void f()\n" -// "{\n" -// " s var;\n" -// " @\n" -// "}\n" -// ) << _("var.") << (QStringList() -// << QLatin1String("j") -// << QLatin1String("s")); - - QTest::newRow("partial_specialization_templated_argument") << _( - "template struct t {};\n" - "\n" - "template struct s { float f; };\n" - "template struct s> { int i; };\n" - "\n" - "void f()\n" - "{\n" - " s> 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 and_type { false_type f; };\n" - "template<> class and_type { true_type t; };\n" - "void func()\n" - "{\n" - " and_type a;\n" - " @;\n" - "}\n" - ) << _("a.") << (QStringList() - << QLatin1String("f") - << QLatin1String("and_type")); - - QTest::newRow("specialization_with_default_value") << _( - "class Foo {};\n" - "template class Temp;\n" - "template<> class Temp { 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\n" - "struct Indirect { _Tp t; };\n" - "\n" - "template\n" - "struct Temp\n" - "{\n" - " typedef T MyT;\n" - " typedef Indirect indirect;\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Temp::indirect i;\n" - " @\n" - "}\n" - ) << _("i.t.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar"));; - QTest::newRow("pointer_indirect_specialization_double_indirection_with_base") << _( "template\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\n" - "struct Temp { typedef _Tp value_type; };\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Temp >::value_type::value_type *p;\n" - " @\n" - "}\n" - ) << _("p->") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("recursive_instantiation_of_template_type_2") << _( - "template\n" - "struct Temp { typedef _Tp value_type; };\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Temp::value_type>::value_type *p;\n" - " @\n" - "}\n" - ) << _("p->") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("template_using_instantiation") << _( - "template\n" - "using T = _Tp;\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " T p;\n" - " @\n" - "}\n" - ) << _("p.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("nested_template_using_instantiation") << _( - "struct Parent {\n" - " template\n" - " using T = _Tp;\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Parent::T p;\n" - " @;\n" - "}\n" - ) << _("p.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("nested_template_using_instantiation_in_template_class") << _( - "template\n" - "struct Parent {\n" - " template\n" - " using T = _Tp;\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Parent::T 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\n" - "struct Traits\n" - "{\n" - " typedef Foo value_type;\n" - "\n" - " template\n" - " using U = T;\n" - "};\n" - "\n" - "template\n" - "struct Temp\n" - "{\n" - " typedef Traits TraitsT;\n" - " typedef typename T::value_type value_type;\n" - " typedef typename TraitsT::template U rebind;\n" - "};\n" - "\n" - "void func()\n" - "{\n" - " typename Temp::rebind>::value_type p;\n" - " @\n" - "}\n" - ) << _("p.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("qualified_name_in_nested_type") << _( - "template\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::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 \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::Nested::type s;\n" - " @\n" - "}\n" - ) << _("s.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("typedefed_decltype_of_template_function") << _( - "template\n" - "static T f();\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void fun()\n" - "{\n" - " decltype(f()) s;\n" - " @\n" - "}\n" - ) << _("s.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("nested_instantiation_typedefed_decltype_declaration_of_template_function") << _( - "template \n" - "struct Temp\n" - "{\n" - " struct Nested\n" - " {\n" - " template static T* __test(...);\n" - " typedef decltype(__test(0)) type;\n" - " };\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Temp::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 struct Foo { T member; };\n" - "typedef Foo 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\n" - "struct allocator\n" - "{\n" - " typedef _Tp value_type;\n" - "\n" - " template\n" - " struct rebind\n" - " { typedef allocator<_Tp1> other; };\n" - "};\n" - "\n" - "template\n" - "struct __alloctr_rebind\n" - "{\n" - " typedef typename _Alloc::template rebind<_Tp>::other __type;\n" - "};\n" - "\n" - "template\n" - "struct allocator_traits\n" - "{\n" - " typedef typename _Alloc::value_type value_type;\n" - "\n" - " template\n" - " using rebind_alloc = typename __alloctr_rebind<_Alloc, _Tp>::__type;\n" - "};\n" - "\n" - "template\n" - "struct iterator_traits { };\n" - "\n" - "template\n" - "struct iterator_traits<_Tp*>\n" - "{\n" - " typedef _Tp* pointer;\n" - "};\n" - "} // namespace std\n" - "\n" - "namespace __gnu_cxx\n" - "{\n" - "template\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\n" - " struct rebind\n" - " { typedef typename _Base_type::template rebind_alloc<_Tp> other; };\n" - "};\n" - "\n" - "template\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\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 >\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 iterator;\n" - "};\n" - "} // namespace std\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " std::vector::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 fa7790a9153..eec2f2e5fe0 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 memberScopes; @@ -1542,26 +1542,26 @@ bool InternalCppCompletionAssistProcessor::globalCompletion(Scope *currentScope) return !m_completions.isEmpty(); } - QList usingBindings; - LookupScope *currentBinding = 0; + QList 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 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 QListlanguageFeatures().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 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 } 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 } 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 return !m_completions.isEmpty(); } -void InternalCppCompletionAssistProcessor::completeNamespace(LookupScope *b) +void InternalCppCompletionAssistProcessor::completeNamespace(ClassOrNamespace *b) { - QSet bindingsVisited; - QList bindingsToVisit; + QSet bindingsVisited; + QList 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 bindingsVisited; - QList bindingsToVisit; + QSet bindingsVisited; + QList 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 signatures; foreach (const LookupItem &lookupItem, results) { - LookupScope *b = lookupScopeFromLookupItem(lookupItem, context); + ClassOrNamespace *b = classOrNamespaceFromLookupItem(lookupItem, context); if (!b) continue; - QListtodo; - QSet processed; + QListtodo; + QSet processed; QList 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 01fd44e5b86..30f88090817 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 &results); bool completeScope(const QList &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 f3a79429541..c70bdb14e5c 100644 --- a/src/plugins/cpptools/cpptoolsreuse.cpp +++ b/src/plugins/cpptools/cpptoolsreuse.cpp @@ -108,7 +108,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 3bc72c00b50..cc5006e63af 100644 --- a/src/plugins/cpptools/symbolfinder.cpp +++ b/src/plugins/cpptools/symbolfinder.cpp @@ -151,7 +151,7 @@ Function *SymbolFinder::findMatchingDefinition(Symbol *declaration, QList 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 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 45236eb1ad9..c1d65f7716d 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/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp index 5c2be000586..3b7e4c52d0f 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 interfaces; - QList nodes; + QList interfaces; + QList 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 > implements; - foreach (LookupScope *b, nodes) { - LookupScope *iface = 0; - foreach (LookupScope *u, b->usings()) { + QHash > 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 baseClasses(LookupScope *b) { - QList usings = b->usings(); - foreach (LookupScope *u, usings) + QList baseClasses(ClassOrNamespace *b) { + QList 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/checksymbols/tst_checksymbols.cpp b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp index 3a39909e3cb..683513f12b6 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 \n" - "struct Base\n" - "{\n" - "};\n" - "\n" - "template\n" - "struct Derived :\n" - " Base<\n" - " typename Derived::type>::type,\n" - " typename Derived::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\n" - "struct Indirect { _Tp t; };\n" - "\n" - "template\n" - "struct Temp\n" - "{\n" - " typedef T MyT;\n" - " typedef Indirect indirect;\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Temp::indirect i;\n" - " i.t.@bar;\n" - "}\n" - ); - QTest::newRow("pointer_indirect_specialization_double_indirection") << _( "template\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\n" - "struct allocator\n" - "{\n" - " typedef _Tp value_type;\n" - "\n" - " template\n" - " struct rebind\n" - " { typedef allocator<_Tp1> other; };\n" - "};\n" - "\n" - "template\n" - "struct __alloctr_rebind\n" - "{\n" - " typedef typename _Alloc::template rebind<_Tp>::other __type;\n" - "};\n" - "\n" - "template\n" - "struct allocator_traits\n" - "{\n" - " typedef typename _Alloc::value_type value_type;\n" - "\n" - " template\n" - " using rebind_alloc = typename __alloctr_rebind<_Alloc, _Tp>::__type;\n" - "};\n" - "\n" - "template\n" - "struct iterator_traits { };\n" - "\n" - "template\n" - "struct iterator_traits<_Tp*>\n" - "{\n" - " typedef _Tp* pointer;\n" - "};\n" - "} // namespace std\n" - "\n" - "namespace __gnu_cxx\n" - "{\n" - "template\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\n" - " struct rebind\n" - " { typedef typename _Base_type::template rebind_alloc<_Tp> other; };\n" - "};\n" - "\n" - "template\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\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 >\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 iterator;\n" - "};\n" - "} // namespace std\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " std::vector::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 deab703a8f6..8347749f436 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 4717c5fc228..2011f03e002 100644 --- a/tests/auto/cplusplus/semantic/tst_semantic.cpp +++ b/tests/auto/cplusplus/semantic/tst_semantic.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,6 @@ #include #include #include -#include //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 doc = document("template class basic_string;"); - 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")); -} - void tst_Semantic::expression_under_cursor_1() { const QString plainText = "void *ptr = foo(10, bar"; From 306c4a695fa83ecd121a2fa5dba00d04446591cf Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 19 Nov 2015 16:23:38 +0100 Subject: [PATCH 16/35] Doc: add missing \l command to fix a link Change-Id: I2af5d8eca8ce40e1c674b7463ddbf71d27fc794d Reviewed-by: Leena Miettinen --- doc/src/overview/creator-target-platforms.qdocinc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/overview/creator-target-platforms.qdocinc b/doc/src/overview/creator-target-platforms.qdocinc index 34cfdc0a2fa..812564c93e7 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 From 1ed73ea36c9fe0d0bbc6106d2825fcdd8caffb62 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 19 Nov 2015 16:29:31 +0100 Subject: [PATCH 17/35] Doc: fix links to previous and next pages ...for moved pages Change-Id: Ic52376b73687676c0e09fefc5a53f10c328c18c8 Reviewed-by: Leena Miettinen --- doc/src/qtquick/qtquick-components.qdoc | 2 +- doc/src/qtquick/qtquick-connection-editor.qdoc | 2 +- doc/src/qtquick/qtquick-designer.qdoc | 2 +- doc/src/qtquick/qtquick-pathview-editor.qdoc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/src/qtquick/qtquick-components.qdoc b/doc/src/qtquick/qtquick-components.qdoc index 6b946f3de72..86b0a1e36ee 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 f57dc9be212..a84022136e8 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 6b8e5cb03ed..b9da283ba32 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 55424c92efe..8e20f3613d2 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 From 62e3e87309e53c4d50f3a564e8e7c3e3a28561bd Mon Sep 17 00:00:00 2001 From: Jochen Becher Date: Tue, 17 Nov 2015 21:37:49 +0100 Subject: [PATCH 18/35] ModelEditor: Fix endless loop with class members Using Q_INVOKABLE in class members led to endless loop. Other qualifiers like Q_SLOT or virtual do work. Task-number: QTCREATORBUG-15347 Change-Id: Id25ee7970b49ed815a86fa76af6cbb3a06405971 Reviewed-by: Tobias Hunger --- .../3rdparty/modeling/qmt/model_widgets_ui/classmembersedit.cpp | 1 + 1 file changed, 1 insertion(+) 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 df4253329c9..d1702f0eed6 100644 --- a/src/libs/3rdparty/modeling/qmt/model_widgets_ui/classmembersedit.cpp +++ b/src/libs/3rdparty/modeling/qmt/model_widgets_ui/classmembersedit.cpp @@ -530,6 +530,7 @@ QList ClassMembersEdit::parse(const QString &text, bool *ok) word = cursor.readWord().toLower(); } else if (word == QStringLiteral("invokable") || word == QStringLiteral("q_invokable")) { member.setProperties(member.getProperties() | MClassMember::PROPERTY_QINVOKABLE); + word = cursor.readWord().toLower(); } else if (word == QStringLiteral(":")) { word = cursor.readWord().toLower(); } else { From 71e84f96461be7e3381b8b07a32aef937681942e Mon Sep 17 00:00:00 2001 From: Martin Kampas Date: Thu, 24 Jul 2014 13:58:32 +0200 Subject: [PATCH 19/35] Abi: Choose word width of 32b for x86 target-triplets Change-Id: I537949d3348024954214a6e271d8ca6194a58f53 Reviewed-by: Tobias Hunger --- src/plugins/projectexplorer/abi.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 10f4ba52bc5..cbf6c128b42 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) From 01b50d2fc3e05920c7aa5bf286d1272214c87b6e Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 11 Nov 2015 11:29:38 +0200 Subject: [PATCH 20/35] Fix invalid long address printing Task-number: QTCREATORBUG-15326 Change-Id: I90b73e757c0ad3fc16ef587e6b4359e6bcb843ea Reviewed-by: Christian Stenger --- share/qtcreator/debugger/dumper.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 07fac849806..8a5b51ddca8 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: From d5ff81e1c5691d2aba2f96fbcf2753056944420b Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Fri, 20 Nov 2015 11:00:04 +0200 Subject: [PATCH 21/35] SSH: Fix GCC 5.2.1 warning in release build warning: 'label' may be used uninitialized in this function I know it doesn't make sense... :) Change-Id: I954ea725f7437d4b31f836134bf59b10f9fbee01 Reviewed-by: Christian Kandeler --- src/libs/ssh/sshkeygenerator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/ssh/sshkeygenerator.cpp b/src/libs/ssh/sshkeygenerator.cpp index 1c6e22db038..6f1800e90d5 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 params; - const char *label; + const char *label = ""; switch (m_type) { case Rsa: { const QSharedPointer rsaKey @@ -197,6 +197,7 @@ void SshKeyGenerator::generateOpenSslPrivateKeyString(const KeyPtr &key) case Ecdsa: params << key.dynamicCast()->private_value(); label = "EC PRIVATE KEY"; + break; } DER_Encoder encoder; From 0275d34dd26b927ac94e2d80467cfb1c03d682e8 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Fri, 20 Nov 2015 11:43:33 +0200 Subject: [PATCH 22/35] QmlDesigner: Fix GCC 5.2.1 warning in release build warning: 't' may be used uninitialized in this function [-Wmaybe-uninitialized] Change-Id: Ic9f87bdb8da36db5371349fb1987d2e9fe66665e Reviewed-by: Orgad Shaneh --- .../qmldesigner/qmldesignerextension/pathtool/pathitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/qmldesignerextension/pathtool/pathitem.cpp b/src/plugins/qmldesigner/qmldesignerextension/pathtool/pathitem.cpp index 7dfb02609cf..b984b3da1ab 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); From 50cbb30911bd549df5e2c49ae315c5bf0bc28e77 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 20 Nov 2015 12:12:08 +0100 Subject: [PATCH 23/35] Doc: remove extra column from table on front page Change-Id: I8ed573305d209f887a6e65623b5a40173493df73 Reviewed-by: Leena Miettinen --- doc/src/qtcreator.qdoc | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/src/qtcreator.qdoc b/doc/src/qtcreator.qdoc index 867d29c231c..27316fc87cc 100644 --- a/doc/src/qtcreator.qdoc +++ b/doc/src/qtcreator.qdoc @@ -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}. From f00280d11d938a4b032703f7fef426b8490b9f32 Mon Sep 17 00:00:00 2001 From: Martin Kampas Date: Fri, 20 Nov 2015 08:10:34 +0100 Subject: [PATCH 24/35] qtcanvas3dapplication wizard: Fix typo ${} -> %{} Change-Id: I248a12ac502d66c331f4584c84ee8a1f1f4ac0a4 Reviewed-by: Tobias Hunger --- .../wizards/projects/qmake/qtcanvas3dapplication/wizard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/wizard.json index c97ae596df7..6b3a2883478 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": [ From 507708131917f047d8ea83041bf6bfdabfba94eb Mon Sep 17 00:00:00 2001 From: Martin Kampas Date: Thu, 19 Nov 2015 12:49:30 +0100 Subject: [PATCH 25/35] Wizards: Fix inconsistent category display names Change-Id: I24d0744351d0065793b8ccb65ba83d8a499f28dd Reviewed-by: Tobias Hunger --- .../wizards/projects/qmlproject/qtquickapplication/wizard.json | 2 +- .../projects/qmlproject/qtquickcontrolsapplication/wizard.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/templates/wizards/projects/qmlproject/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmlproject/qtquickapplication/wizard.json index 68476a9357e..29a51b8e41a 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 57b53777505..7d601d3dbd7 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" ], From 6c74ef237a0ec7e3d57d1af559ed91322c2016a2 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Fri, 20 Nov 2015 10:45:42 +0200 Subject: [PATCH 26/35] Git: Avoid duplicate check for modified files Change-Id: I05e09434944706a61cc079c30d37309eea5019f5 Reviewed-by: Tobias Hunger --- src/plugins/git/gitplugin.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index b3f433dce56..1aba1fe9a12 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -748,8 +748,6 @@ void GitPlugin::undoFileChanges(bool revertStaging) void GitPlugin::undoUnstagedFileChanges() { - if (!DocumentManager::saveAllModifiedDocuments()) - return; undoFileChanges(false); } From a941f7b2165335cfa7704e07eaf9306bc44a2add Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Fri, 20 Nov 2015 10:39:00 +0200 Subject: [PATCH 27/35] Mercurial: Fix "view" invoked from editor The editor is initialized with a SLOT reference to view. Change-Id: Ia793878f12c8caf8a71b565f78bf05db6bac74ca Reviewed-by: Tobias Hunger --- src/plugins/mercurial/mercurialclient.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/mercurial/mercurialclient.h b/src/plugins/mercurial/mercurialclient.h index 80c9067e1c6..c50aeaeacdb 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()); From 02e387f5d827583db7666746700d05905739abee Mon Sep 17 00:00:00 2001 From: Sergey Belyashov Date: Mon, 9 Nov 2015 12:36:20 +0300 Subject: [PATCH 28/35] Update Russian translation Change-Id: I35f09b4905f325f712b9d506149412dfcbb51bb5 Reviewed-by: Denis Shienkov Reviewed-by: Oswald Buddenhagen --- share/qtcreator/translations/qtcreator_ru.ts | 66 ++++++++------------ 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index 51559890faf..2090cf9481c 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. Core plugin is disabled. Базовый модуль отключён. - - No valid theme "%1" - Подходящая тема «%1» не обнаружена - ApplicationWindowSpecifics @@ -5382,6 +5378,10 @@ Continue? Core::Internal::CorePlugin + + No themes found in installation. + Темы не установлены. + The current date (ISO). Текущая дата (ISO). @@ -8285,26 +8285,6 @@ In addition, Shift+Enter inserts an escape character at the cursor position and Form - - Code Completion and Semantic Highlighting - Дополнение и подсветка кода - - - C - C - - - C++ - C++ - - - Objective C - Objective C - - - Objective C++ - Objective C++ - Pre-compiled Headers Прекомпилированные заголовки @@ -8318,8 +8298,20 @@ In addition, Shift+Enter inserts an escape character at the cursor position and Игнорировать прекомпилированные заголовки - Headers - Заголовочные + <i>Activate the Clang Code Model plugin to enable the options here.</i> + <i>Включите модуль Clang Code Model, чтобы менять настройки.</i> + + + Use Clang Code Model + Использовать модель кода Clang + + + Append additional command line options to Clang, one per line. <i>Use this with care.</i> + Дополнительные параметры командной строки Clang, по одной на строке.<br><i>Используйте их с осторожностью.</i> + + + Reset Options + Сбросить @@ -10437,14 +10429,6 @@ Flags: %3 Changes the font size in the debugger views when the font size in the main editor changes. Менять размер шрифта в окне отладчика при изменении его в основном окне редактора. - - Populates the source file view automatically. This might slow down debugger startup considerably. - Автоматическое заполнение просмотра файлов исходных текстов. Может замедлить процесс запуска отладчика. - - - Populate source file view automatically - Автоматически заполнять представление исходных текстов - Switch to previous mode on debugger exit Переключаться в предыдущий режим при завершении отладчика @@ -11364,10 +11348,6 @@ Qt Creator не может подключиться к нему. Use Tooltips in Stack View when Debugging Подсказки в обзоре стека при отладке - - List Source Files - Показать файлы исходников - Skip Known Frames Пропустить известные кадры @@ -22142,6 +22122,10 @@ Ids must begin with a lowercase letter. ProjectExplorer::Internal::DependenciesWidget + + Synchronize configuration + Синхронизировать конфигурацию + Synchronize active kit, build, and deploy configuration between projects. Сихронизировать у проектов текущий комплект и конфигурации сборки и установки. @@ -34043,7 +34027,7 @@ with a password, which you can enter below. TextEditor::FindInFiles - Files on File System + Files in File System Файлы в системе @@ -38740,6 +38724,10 @@ should a repository require SSH-authentication (see documentation on SSH and the WinRt::Internal::WinRtDebugSupport + + Not enough free ports for QML debugging. + Недостаточно свободных портов для отладки QML. + The WinRT debugging helper is missing from your Qt Creator installation. It was assumed to be located at %1 Помощник отладчика WinRT отсутствует в составе установки вашего Qt Creator. Предполагается, что он находится в %1 From 927767c6452c613589a06d4509f89a3912ddec8a Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 20 Nov 2015 15:08:51 +0100 Subject: [PATCH 29/35] QmlDesigner: Fix crash We removed support for non default properties in the navigator. But the model still allows QML code like this: toolBar: ToolBar {...} In this case ToolBar is not visible in the navigator. But the ToolBar is available/visible in the form editor. Reparenting anything to ToolBar did crash. Eventually we have to re enable non default properties, but this patch only fixes the crash. Task-number: QTCREATORBUG-15111 Change-Id: Ifa037975c99762fb8067afffa118332044842d7f Reviewed-by: Eike Ziller Reviewed-by: Tim Jenssen --- .../qmldesigner/components/navigator/navigatortreemodel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 5abbc6169d2..1e345f306f5 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -565,7 +565,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()); From 708fda792e67a27ae48c6551318ef4c3a08728df Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 20 Nov 2015 14:52:51 +0100 Subject: [PATCH 30/35] Doc: make umbrella topics consistent with browsing sequences Some topics had ended up in the wrong top level topic, as compared with the manual structure. Change-Id: I03bc2fa2c0cbc8492c2bcec58eeddcd04d249a96 Reviewed-by: Eike Ziller --- doc/src/editors/creator-coding.qdoc | 21 ++++--------------- .../editors/creator-editors-writing-code.qdoc | 19 +++++++++++++++++ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/doc/src/editors/creator-coding.qdoc b/doc/src/editors/creator-coding.qdoc index 3cb58bf3c2d..9fcb5e18a88 100644 --- a/doc/src/editors/creator-coding.qdoc +++ b/doc/src/editors/creator-coding.qdoc @@ -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} + \li \l{Modeling} - 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. + 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 8ee82d22295..78d1ece3525 100644 --- a/doc/src/editors/creator-editors-writing-code.qdoc +++ b/doc/src/editors/creator-editors-writing-code.qdoc @@ -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 + */ From 7081b7aecb63270103c4f41f3a020842993dce90 Mon Sep 17 00:00:00 2001 From: Martin Kampas Date: Fri, 20 Nov 2015 12:41:24 +0100 Subject: [PATCH 31/35] PathChooser: Fix segfault on destruction I was only able to crash it with the Mer plugin (not in tree). Change-Id: Ie478f74c48ac6686418207fd1af8b727bcfed3cd Reviewed-by: Tobias Hunger --- src/libs/utils/pathchooser.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 997f4c2f76f..42889793958 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; } From 8745c0a261a0ac70a42488983fb9297097da1545 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 18 Nov 2015 15:26:28 +0100 Subject: [PATCH 32/35] Clang: Activate clang crash recovery Change-Id: I382a4d433ef64dedfeb39034df93579e7eb2580c Reviewed-by: Nikolai Kosjar --- src/tools/clangbackend/clangbackendmain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/clangbackend/clangbackendmain.cpp b/src/tools/clangbackend/clangbackendmain.cpp index 428d55add64..6b9e30fc16b 100644 --- a/src/tools/clangbackend/clangbackendmain.cpp +++ b/src/tools/clangbackend/clangbackendmain.cpp @@ -53,6 +53,8 @@ int main(int argc, char *argv[]) ClangBackEnd::Messages::registerMessages(); + clang_toggleCrashRecovery(true); + ClangBackEnd::ClangIpcServer clangIpcServer; ClangBackEnd::ConnectionServer connectionServer(application.arguments()[1]); connectionServer.start(); From a2988a2800900c831f138a60c2c5a07aae69d7a8 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 17 Nov 2015 13:57:50 +0100 Subject: [PATCH 33/35] Clang: Enable stack traces Change-Id: Ia7b8b7aa598f74e2c80e27f328ac5ddb410c043e Reviewed-by: Nikolai Kosjar --- src/tools/clangbackend/clangbackendmain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/clangbackend/clangbackendmain.cpp b/src/tools/clangbackend/clangbackendmain.cpp index 6b9e30fc16b..33a6c1660e5 100644 --- a/src/tools/clangbackend/clangbackendmain.cpp +++ b/src/tools/clangbackend/clangbackendmain.cpp @@ -54,6 +54,7 @@ int main(int argc, char *argv[]) ClangBackEnd::Messages::registerMessages(); clang_toggleCrashRecovery(true); + clang_enableStackTraces(); ClangBackEnd::ClangIpcServer clangIpcServer; ClangBackEnd::ConnectionServer connectionServer(application.arguments()[1]); From 114e52b3f08fea8af5c9ce870121988128824c5c Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Fri, 30 Oct 2015 17:33:01 +0100 Subject: [PATCH 34/35] Squish: Update video's title in tst_WELP04 Change-Id: Ibf9d75324332be4e3223323ed8aa4cc34b01612e Reviewed-by: Christian Stenger --- tests/system/suite_WELP/tst_WELP04/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/suite_WELP/tst_WELP04/test.py b/tests/system/suite_WELP/tst_WELP04/test.py index 9cc23275d00..cf10169042a 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") From 499589096a54181bfdbfad5bc2ba50dc945d0934 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Fri, 20 Nov 2015 08:39:09 -0800 Subject: [PATCH 35/35] Add missing include. Change-Id: I3ccc9c96a4a4ebc974424cbee7289a8fa0fbc196 Reviewed-by: Orgad Shaneh --- src/shared/json/json.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/json/json.cpp b/src/shared/json/json.cpp index c40aa3dc1f9..75d313c9e29 100644 --- a/src/shared/json/json.cpp +++ b/src/shared/json/json.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include