1 // RUN: %check_clang_tidy %s cata-translator-comments %t -- -plugins=%cata_plugin --
2 
3 // check_clang_tidy uses -nostdinc++, so we add dummy declaration of std::string here
4 namespace std
5 {
6 template<class CharT, class Traits = void, class Allocator = void>
7 class basic_string
8 {
9     public:
10         basic_string();
11         basic_string( const CharT * );
12         CharT *c_str();
13         const CharT *c_str() const;
14 };
15 using string = basic_string<char>;
16 } // namespace std
17 
18 // check_clang_tidy uses -nostdinc++, so we add dummy translation interface here instead of including translations.h
19 #define translate_marker( s ) ( s )
20 #define translate_marker_context( c, s ) ( s )
21 // mimic how it's declared in translation.h
22 #define _( msg ) \
23     ( ( []( const auto & arg ) { \
24         return arg; \
25     } )( msg ) )
26 
27 const char *gettext( const char * );
28 const char *pgettext( const char *, const char * );
29 const char *ngettext( const char *, const char *, int );
30 const char *npgettext( const char *, const char *, const char *, int );
31 
32 class translation
33 {
34     public:
35         static translation to_translation( const std::string & );
36         static translation to_translation( const std::string &, const std::string & );
37         static translation pl_translation( const std::string &, const std::string & );
38         static translation pl_translation( const std::string &, const std::string &, const std::string & );
39         static translation no_translation( const std::string & );
40 };
41 
42 translation to_translation( const std::string & );
43 translation to_translation( const std::string &, const std::string & );
44 translation pl_translation( const std::string &, const std::string & );
45 translation pl_translation( const std::string &, const std::string &, const std::string & );
46 translation no_translation( const std::string & );
47 
foo()48 void foo()
49 {
50     // translation markers only accepts string literals as arguments
51     static_cast<void>( translate_marker( "bar" ) );
52     static_cast<void>( translate_marker( R"(foo)" "bar" ) );
53     static_cast<void>( translate_marker_context( "foo", "bar" ) );
54 
55     static_cast<void>( translate_marker( ( "bar" ) ) );
56     // CHECK-MESSAGES: [[@LINE-1]]:42: warning: Translation marker macros only accepts string literal arguments
57     static_cast<void>( translate_marker_context( "foo", ( "bar" ) ) );
58     // CHECK-MESSAGES: [[@LINE-1]]:57: warning: Translation marker macros only accepts string literal arguments
59 #define pass_through( x ) x
60     static_cast<void>( translate_marker( pass_through( "bar" ) ) );
61     // CHECK-MESSAGES: [[@LINE-1]]:42: warning: Translation marker macros only accepts string literal arguments
62     static_cast<void>( translate_marker_context(, "bar" ) );
63     // CHECK-MESSAGES: [[@LINE-1]]:49: warning: Empty argument to a translation marker macro
64 
65     // valid translator comments
66 
67     // ~xgettext will treat this as a translator comment, but we ignore it
68     // to allow using the tilde (~) inside normal comments
69 
70     //~ bar
71     _( "bar" );
72 
73     ngettext( /*~ foo */ ( "bar" ), _( "baz" ), 0 );
74 
75     //~ bar
76     gettext( "bar" );
77 
78     //~bar
79     ngettext( "bar", "baz", 1 );
80 
81     /*~ bar */ to_translation( "bar" );
82 
83     /*~ bar */
84     pl_translation( "bar", "baz" );
85 
86     _( /*~ bar */ "bar" );
87 
88     /*~
89     bar*/
90     _( "bar" );
91 
92     //~ bar
93     pgettext( "foo", "bar" );
94 
95     //~ bark
96     static_cast<void>( translate_marker( "bar" ) );
97 
98     static_cast<void>( translate_marker_context( "foo", /*~ bard */ "bar" ) );
99 
100     // misplaced translator comments
101 
102     //~ barbarian
103     const char *bar = "bar";
104     static_cast<void>( bar );
105     _( "bar" );
106     // CHECK-MESSAGES: [[@LINE-4]]:5: warning: Translator comment without a matching raw string
107 
108     _( "bar" );
109     //~ barbara
110     // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Translator comment without a matching raw string
111 
112     _( "bar" /*~ banana */ );
113     // CHECK-MESSAGES: [[@LINE-1]]:14: warning: Translator comment without a matching raw string
114 
115     //~ barb
116     _( ( "bar" ) );
117     // CHECK-MESSAGES: [[@LINE-2]]:5: warning: Translator comment without a matching raw string
118 
119     //~ barf
120     pgettext( ( "foo" ), "bar" );
121     // CHECK-MESSAGES: [[@LINE-2]]:5: warning: Translator comment without a matching raw string
122 
123     /*~
124     barnacle */
125     npgettext( "foo",
126                "bar", "baz", 2 );
127     // CHECK-MESSAGES: [[@LINE-4]]:5: warning: Translator comment without a matching raw string
128 
129     //~ barn
130     npgettext( "foo", "bar", ( "baz" ), 3 );
131     // CHECK-MESSAGES: [[@LINE-2]]:5: warning: Translator comment without a matching raw string
132 
133     //~ baron
134     to_translation( "foo", { "bar" } );
135     // CHECK-MESSAGES: [[@LINE-2]]:5: warning: Translator comment without a matching raw string
136 
137     //~ barricade
138     to_translation( "foo", ( "bar" ) );
139     // CHECK-MESSAGES: [[@LINE-2]]:5: warning: Translator comment without a matching raw string
140 
141     //~ bartender
142     to_translation( "foo", std::string( "bar" ) );
143     // CHECK-MESSAGES: [[@LINE-2]]:5: warning: Translator comment without a matching raw string
144 
145     //~ barbeque
146     to_translation( "foo",
147                     "bar" );
148     // CHECK-MESSAGES: [[@LINE-3]]:5: warning: Translator comment without a matching raw string
149 }
150 
151 //~ barometer
152 // CHECK-MESSAGES: [[@LINE-1]]:1: warning: Translator comment without a matching raw string
153