aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrzemyslaw Gorszkowski <pgorszkowski@gmail.com>2017-05-24 11:08:24 +0200
committerPrzemyslaw Gorszkowski <pgorszkowski@gmail.com>2017-06-15 17:18:20 +0000
commit7bcf4831891536992607b5a7b43675590790ee59 (patch)
tree4b71a2479d5dd31d500d2d0a8c17b4538866ee42
parentd3d3e2ace5485d3812d98b5b3f3ccd8e7c12b4f1 (diff)
C++: fix code completion of stl containers in internal code model
This fix makes some trick and replaces existing typedef of 'pointer' to the simplest one(only in class unique_ptr), e.g.: template <class _Tp> class unique_ptr { typedef some_strange_things pointer; pointer operator->(); } is replace with template <class _Tp> class unique_ptr { typedef _Tp* pointer; pointer operator->(); } In most of the implementation of unique_ptr it should work. Similar approach is done for std::list, std::vector, std::queue, std::set, std::multiset, std::unordered_set. It is done in this hacky way to omit problems with cyclic and complex resolving of typedefs. Change-Id: I1363dfc5e23d3cd2fa7af7fc27423bfbac2d894d Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
-rw-r--r--src/libs/3rdparty/cplusplus/Symbols.cpp106
-rw-r--r--src/libs/cplusplus/ResolveExpression.cpp5
-rw-r--r--src/plugins/cpptools/cppcompletion_test.cpp163
3 files changed, 266 insertions, 8 deletions
diff --git a/src/libs/3rdparty/cplusplus/Symbols.cpp b/src/libs/3rdparty/cplusplus/Symbols.cpp
index 253bb04788..f7423e7742 100644
--- a/src/libs/3rdparty/cplusplus/Symbols.cpp
+++ b/src/libs/3rdparty/cplusplus/Symbols.cpp
@@ -18,13 +18,18 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-#include "Symbols.h"
-#include "Names.h"
-#include "TypeVisitor.h"
-#include "SymbolVisitor.h"
+#include "Control.h"
+#include "CoreTypes.h"
+#include "Literals.h"
#include "Matcher.h"
+#include "Names.h"
#include "Scope.h"
+#include "Symbols.h"
+#include "SymbolVisitor.h"
#include "Templates.h"
+#include "TypeVisitor.h"
+
+#include <cstring>
using namespace CPlusPlus;
@@ -99,7 +104,98 @@ Declaration::Declaration(Clone *clone, Subst *subst, Declaration *original)
: Symbol(clone, subst, original)
, _type(clone->type(original->_type, subst))
, _initializer(clone->stringLiteral(original->_initializer))
-{ }
+{
+ const char* nameId = nullptr;
+ if (const Identifier* identifier = name()->identifier())
+ nameId = identifier->chars();
+ else
+ return;
+
+ Class *enClass = original->enclosingClass();
+ const char* enClassNameId = nullptr;
+ if (enClass && enClass->name() && enClass->name()->identifier()) {
+ enClassNameId = enClass->name()->identifier()->chars();
+ } else {
+ return;
+ }
+
+ if (!enClassNameId)
+ return;
+
+ Template *templSpec = enClass->enclosingTemplate();
+ const char* enNamespaceNameId = nullptr;
+ if (templSpec) {
+ if (Namespace* ns = templSpec->enclosingNamespace()) {
+ if (ns->isInline())
+ ns = ns->enclosingNamespace();
+
+ if (ns->name() && ns->name()->identifier())
+ enNamespaceNameId =ns->name()->identifier()->chars();
+ }
+ }
+
+ if (!enNamespaceNameId || templSpec->templateParameterCount() < 1)
+ return;
+
+ const Name *firstTemplParamName = nullptr;
+ if (const TypenameArgument *templParam =
+ templSpec->templateParameterAt(0)->asTypenameArgument()) {
+ firstTemplParamName = templParam->name();
+ }
+
+ if (!firstTemplParamName)
+ return;
+
+ FullySpecifiedType newType;
+ if (std::strcmp(enNamespaceNameId, "std") == 0 ||
+ std::strcmp(enNamespaceNameId, "__cxx11") == 0) {
+ if (std::strcmp(enClassNameId, "unique_ptr") == 0) {
+ if (std::strcmp(nameId, "pointer") == 0) {
+ newType = clone->type(subst->apply(firstTemplParamName), 0);
+ newType = FullySpecifiedType(clone->control()->pointerType(newType));
+ }
+ } else if (std::strcmp(enClassNameId, "list") == 0 ||
+ std::strcmp(enClassNameId, "forward_list") == 0 ||
+ std::strcmp(enClassNameId, "vector") == 0 ||
+ std::strcmp(enClassNameId, "queue") == 0 ||
+ std::strcmp(enClassNameId, "deque") == 0 ||
+ std::strcmp(enClassNameId, "set") == 0 ||
+ std::strcmp(enClassNameId, "unordered_set") == 0 ||
+ std::strcmp(enClassNameId, "multiset") == 0 ||
+ std::strcmp(enClassNameId, "array") == 0) {
+ if (std::strcmp(nameId, "reference") == 0 ||
+ std::strcmp(nameId, "const_reference") == 0) {
+ newType = clone->type(subst->apply(firstTemplParamName), 0);
+ } else if (std::strcmp(nameId, "iterator") == 0 ||
+ std::strcmp(nameId, "reverse_iterator") == 0 ||
+ std::strcmp(nameId, "const_reverse_iterator") == 0 ||
+ std::strcmp(nameId, "const_iterator") == 0) {
+ newType = clone->type(subst->apply(firstTemplParamName), 0);
+ newType = FullySpecifiedType(clone->control()->pointerType(newType));
+ }
+ } else if (std::strcmp(enClassNameId, "_Hash") == 0 ||
+ std::strcmp(enClassNameId, "_Tree") == 0 ) {
+ if (std::strcmp(nameId, "iterator") == 0 ||
+ std::strcmp(nameId, "reverse_iterator") == 0 ||
+ std::strcmp(nameId, "const_reverse_iterator") == 0 ||
+ std::strcmp(nameId, "const_iterator") == 0) {
+ FullySpecifiedType clonedType = clone->type(subst->apply(firstTemplParamName), 0);
+ if (NamedType *namedType = clonedType.type()->asNamedType()) {
+ if (const TemplateNameId * templateNameId =
+ namedType->name()->asTemplateNameId()) {
+ if (templateNameId->templateArgumentCount()) {
+ newType = clone->type(templateNameId->templateArgumentAt(0), 0);
+ newType = FullySpecifiedType(clone->control()->pointerType(newType));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (newType.isValid())
+ _type = newType;
+}
Declaration::~Declaration()
{ }
diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
index 182eda1d59..37b9ce8b30 100644
--- a/src/libs/cplusplus/ResolveExpression.cpp
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -950,9 +950,8 @@ bool ResolveExpression::visit(ArrayAccessAST *ast)
foreach (const LookupItem &r, b->find(arrayAccessOp)) {
Symbol *overload = r.declaration();
if (Function *funTy = overload->type()->asFunctionType()) {
- if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType())
- // ### TODO: check the actual arguments
- addResult(proto->returnType().simplified(), scope);
+ // ### TODO: check the actual arguments
+ addResult(funTy->returnType().simplified(), scope, b);
}
}
diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp
index 1fd80aad13..b494476351 100644
--- a/src/plugins/cpptools/cppcompletion_test.cpp
+++ b/src/plugins/cpptools/cppcompletion_test.cpp
@@ -2584,6 +2584,169 @@ void CppToolsPlugin::test_completion_data()
" @\n"
"}\n"
) << _("t.p->") << QStringList({"Foo", "bar"});
+
+ QTest::newRow("fix_code_completion_for_unique_ptr_operator_arrow") << _(
+ "namespace std {\n"
+ "template<typename _Tp>\n"
+ "struct unique_ptr\n"
+ "{\n"
+ " typedef FOO pointer;\n"
+ " pointer operator->();\n"
+ "};\n"
+ "}\n"
+ "\n"
+ "struct Foo { int bar; };\n"
+ "\n"
+ "void func()\n"
+ "{\n"
+ " std::unique_ptr<Foo> ptr;\n"
+ " @\n"
+ "}\n"
+ ) << _("ptr->") << QStringList({"Foo", "bar"});
+ QTest::newRow("fix_code_completion_for_unique_ptr_method_get") << _(
+ "namespace std {\n"
+ "template<typename _Tp>\n"
+ "struct unique_ptr\n"
+ "{\n"
+ " typedef FOO pointer;\n"
+ " pointer get();\n"
+ "};\n"
+ "}\n"
+ "\n"
+ "struct Foo { int bar; };\n"
+ "\n"
+ "void func()\n"
+ "{\n"
+ " std::unique_ptr<Foo> ptr;\n"
+ " @\n"
+ "}\n"
+ ) << _("ptr.get()->") << QStringList({"Foo", "bar"});
+ QTest::newRow("fix_code_completion_for_std_vector_method_at") << _(
+ "namespace std {\n"
+ "template<typename _Tp>\n"
+ "struct vector\n"
+ "{\n"
+ " typedef FOO reference;\n"
+ " reference at(size_t i);\n"
+ "};\n"
+ "}\n"
+ "\n"
+ "struct Foo { int bar; };\n"
+ "\n"
+ "void func()\n"
+ "{\n"
+ " std::vector<Foo> v;\n"
+ " @\n"
+ "}\n"
+ ) << _("v.at(0).") << QStringList({"Foo", "bar"});
+ QTest::newRow("fix_code_completion_for_std_vector_operator_square_brackets") << _(
+ "namespace std {\n"
+ "template<typename _Tp>\n"
+ "struct vector\n"
+ "{\n"
+ " typedef FOO reference;\n"
+ " reference operator[](size_t i);\n"
+ "};\n"
+ "}\n"
+ "\n"
+ "struct Foo { int bar; };\n"
+ "\n"
+ "void func()\n"
+ "{\n"
+ " std::vector<Foo> v;\n"
+ " @\n"
+ "}\n"
+ ) << _("v[0].") << QStringList({"Foo", "bar"});
+ QTest::newRow("fix_code_completion_for_std_list_method_front") << _(
+ "namespace std {\n"
+ "template<typename _Tp>\n"
+ "struct list\n"
+ "{\n"
+ " typedef FOO reference;\n"
+ " reference front();\n"
+ "};\n"
+ "}\n"
+ "\n"
+ "struct Foo { int bar; };\n"
+ "\n"
+ "void func()\n"
+ "{\n"
+ " std::list<Foo> l;\n"
+ " @\n"
+ "}\n"
+ ) << _("l.front().") << QStringList({"Foo", "bar"});
+ QTest::newRow("fix_code_completion_for_std_queue_method_front") << _(
+ "namespace std {\n"
+ "template<typename _Tp>\n"
+ "struct queue\n"
+ "{\n"
+ " typedef FOO reference;\n"
+ " reference front();\n"
+ "};\n"
+ "}\n"
+ "\n"
+ "struct Foo { int bar; };\n"
+ "\n"
+ "void func()\n"
+ "{\n"
+ " std::queue<Foo> l;\n"
+ " @\n"
+ "}\n"
+ ) << _("l.front().") << QStringList({"Foo", "bar"});
+ QTest::newRow("fix_code_completion_for_std_set_method_begin") << _(
+ "namespace std {\n"
+ "template<typename _Tp>\n"
+ "struct set\n"
+ "{\n"
+ " typedef FOO iterator;\n"
+ " iterator begin();\n"
+ "};\n"
+ "}\n"
+ "\n"
+ "struct Foo { int bar; };\n"
+ "\n"
+ "void func()\n"
+ "{\n"
+ " std::set<Foo> s;\n"
+ " @\n"
+ "}\n"
+ ) << _("s.begin()->") << QStringList({"Foo", "bar"});
+ QTest::newRow("fix_code_completion_for_std_multiset_method_begin") << _(
+ "namespace std {\n"
+ "template<typename _Tp>\n"
+ "struct multiset\n"
+ "{\n"
+ " typedef FOO iterator;\n"
+ " iterator begin();\n"
+ "};\n"
+ "}\n"
+ "\n"
+ "struct Foo { int bar; };\n"
+ "\n"
+ "void func()\n"
+ "{\n"
+ " std::multiset<Foo> s;\n"
+ " @\n"
+ "}\n"
+ ) << _("s.begin()->") << QStringList({"Foo", "bar"});
+ QTest::newRow("fix_code_completion_for_std_unordered_set_method_begin") << _(
+ "namespace std {\n"
+ "template<typename _Tp>\n"
+ "struct unordered_set\n"
+ "{\n"
+ " typedef FOO iterator;\n"
+ " iterator begin();\n"
+ "};\n"
+ "}\n"
+ "\n"
+ "struct Foo { int bar; };\n"
+ "\n"
+ "void func()\n"
+ "{\n"
+ " std::unordered_set<Foo> s;\n"
+ " @\n"
+ "}\n"
+ ) << _("s.begin()->") << QStringList({"Foo", "bar"});
}
void CppToolsPlugin::test_completion_member_access_operator()