// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only


























// IMPORTANT!!!! If you want to add testdata to this file,
// always add it to the end in order to not change the linenumbers of translations!!!
#include <QtCore>
#include <QtGui>
#include <QtWidgets/QMainWindow>
//
// Test namespace scoping
//

class D : public QObject {
    Q_OBJECT
    public:
    QString foo() {
        return tr("test", "D");
    }

};

namespace A {

    class C : public QObject {
        Q_OBJECT
        public:
        void foo();
    };

    void C::foo() {
        tr("Bla", "A::C");
    }

    void goo() {
        C::tr("Bla", "A::C");       // Is identical to the previous tr(), (same context, sourcetext and comment,
                                    // so it should not add another entry to the list of messages)
    }

    void goo2() {
        C::tr("Bla 2", "A::C");     //Should be in the same namespace as the previous tr()
    }

}


namespace X {

    class D : public QObject {
        Q_OBJECT
        public:

    };

    class E : public QObject {
        Q_OBJECT
        public:
        void foo() { D::tr("foo", "D"); }  // Note that this is X::D from 440 on
    };


    namespace Y {
        class E : public QObject {
            Q_OBJECT

        };

        class C : public QObject {
            Q_OBJECT
            void foo();
        };

        void C::foo() {
            tr("Bla", "X::Y::C");
        }

        void goo() {
            D::tr("Bla", "X::D");   //This should be assigned to the X::D context
        }

        void goo2() {
            E::tr("Bla", "X::Y::E");   //This should be assigned to the X::Y::E context
            Y::E::tr("Bla", "X::Y::E");   //This should be assigned to the X::Y::E context
        }

    }; // namespace Y

    class F : public QObject {
        Q_OBJECT
        inline void inlinefunc() {
            tr("inline function", "X::F");
        }
    };
} // namespace X

namespace ico {
    namespace foo {
        class A : public QObject {
            A();
        };

        A::A() {
            tr("myfoo", "ico::foo::A");
            QObject::tr("task 161186", "QObject");
        }
    }
}

namespace AA {
class C {};
}

/**
 * the context of a message should not be affected by any inherited classes
 *
 * Keep this disabled for now, but at a long-term range it should work.
 */
namespace Gui {
    class MainWindow : public QMainWindow,
                    public AA::C
    {
        Q_OBJECT
public:
        MainWindow()
        {
            tr("More bla", "Gui::MainWindow");
        }

    };
} //namespace Gui


namespace A1 {
    class AB : public QObject {
        Q_OBJECT
        public:

        friend class OtherClass;

        QString inlineFuncAfterFriendDeclaration() const {
            return tr("inlineFuncAfterFriendDeclaration", "A1::AB");
        }
    };
    class B : AB {
        Q_OBJECT
        public:
        QString foo() const { return tr("foo", "A1::B"); }
    };

    // This is valid C++ too....
    class V : virtual AB {
        Q_OBJECT
        public:
        QString bar() const { return tr("bar", "A1::V"); }
    };

    class W : virtual public AB {
        Q_OBJECT
        public:
        QString baz() const { return tr("baz", "A1::W"); }
    };
}

class ForwardDecl;


class B1 : public QObject {
};

class C1 : public QObject {
};

namespace A1 {

class B2 : public QObject {
};

}

void func1()
{
    B1::tr("test TRANSLATOR comment (1)", "B1");

}

using namespace A1;
/*
    TRANSLATOR A1::B2
*/
void func2()
{
    B2::tr("test TRANSLATOR comment (2)", "A1::B2");
    C1::tr("test TRANSLATOR comment (3)", "C1");
}

void func3()
{
    B2::tr("test TRANSLATOR comment (4)", "A1::B2");
}

/*
    TRANSLATOR B2
    This is a comment to the translator.
*/
void func4()
{
    B2::tr("test TRANSLATOR comment (5)", "A1::B2");
}

namespace A1 {
namespace B3 {
class C2 : public QObject {
QString foo();
};
}
}

namespace D1 = A1::B3;
using namespace D1;

// TRANSLATOR A1::B3::C2
QString C2::foo()
{
    return tr("test TRANSLATOR comment (6)", "A1::B3::C2"); // 4.4 screws up
}
namespace Fooish {
  struct toto {
  Q_DECLARE_TR_FUNCTIONS(Bears::And::Spiders)
    QString bar(); };
}

QString Fooish::toto::bar()
{
    return tr("whatever the context", "Bears::And::Spiders");
}


int main(int /*argc*/, char ** /*argv*/) {
    return 0;
}


// QTBUG-140636: Return type vs method qualification disambiguation
// Types from <external_types.h> use angle brackets, so lupdate looks for them in the
// configured paths (and not the relative locations), and if not found, they are not qualified.
// Without the fix, these produce: "Qualifying with unknown namespace/class ::Namespace"
#include <external_types.h>

// Basic namespaced return type
class TestClass1_Widget : public QObject {
    Q_OBJECT
};

Tasking::GroupItem testFunction1()
{
    TestClass1_Widget::tr("test1: basic return type");
}

// Deeply nested return type
namespace MyNS {
class TestClass2 : public QObject {
    Q_OBJECT
public:
    External::Deeply::Nested::Type method();
};
}

External::Deeply::Nested::Type MyNS::TestClass2::method()
{
    tr("test2: nested return type");
    return {};
}

// Trailing return type syntax
class TestClass3 : public QObject {
    Q_OBJECT
public:
    auto method() -> UndefinedNS::RetType;
};

auto TestClass3::method() -> UndefinedNS::RetType
{
    tr("test3: trailing return type");
    return {};
}

// Template return type
#include <vector>
class TestClass4 : public QObject {
    Q_OBJECT
public:
    std::vector<ThirdParty::Item> getItems();
};

std::vector<ThirdParty::Item> TestClass4::getItems()
{
    tr("test4: template return type");
    return {};
}

// Const reference return
class TestClass5 : public QObject {
    Q_OBJECT
public:
    const LibraryNS::Data& getData() const noexcept;
};

const LibraryNS::Data& TestClass5::getData() const noexcept
{
    tr("test5: const reference return");
    static LibraryNS::Data d;
    return d;
}

// Operator overload return type
class TestClass6 : public QObject {
    Q_OBJECT
public:
    OperatorNS::Type operator<<(const OperatorNS::Type& t);
};

OperatorNS::Type TestClass6::operator<<(const OperatorNS::Type& t)
{
    tr("test6: operator overload");
    return t;
}

// - If the user code contains a function named "tr" (same name as our tr
//   function), lupdate wrongly clears the parsed prospectiveContext.
//   When lupdate parses the arguments of that function, upon
//   encountering two Tok_Idents in the arguments
//   lupdate wrongly assumes it is parsing an instance of
//   Tok_Ident::Tok_ident... in the return type of a method signature.
//   In that case, since such instance doesn't define context, lupdate
//   clears the prospectiveContext.
// - Test that two ident tokens (int num) as parameters of a function
//   named "tr" don't result in clearing prospectiveContext in the cpp parser
namespace MyNamespace {
class MyClass : public QObject
{
    Q_OBJECT
    void tr(int num);
};
void MyClass::tr(int num)
{
    if (num)
        tr("translation");
}
} // namespace MyNamespace

// Test unresolved class context (class not defined in this file)
void UnknownClass::methodWithTr()
{
    QObject::tr("test7: unresolved class context");
}

//#include "main.moc"
