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's avatarNikolai Kosjar <nikolai.kosjar@qt.io>
parent d3d3e2ac
......@@ -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()
{ }
......
......@@ -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);
}
}
......
......@@ -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()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment