David Blaikie | 5f31f08 | 2011-10-18 05:54:07 +0000 | [diff] [blame] | 1 | // RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s |
Kaelyn Uhrain | fac9467 | 2011-10-11 01:02:41 +0000 | [diff] [blame] | 2 | |
| 3 | struct errc { |
| 4 | int v_; |
| 5 | operator int() const {return v_;} |
| 6 | }; |
| 7 | |
| 8 | class error_condition |
| 9 | { |
| 10 | int _val_; |
| 11 | public: |
| 12 | error_condition() : _val_(0) {} |
| 13 | |
| 14 | error_condition(int _val) |
| 15 | : _val_(_val) {} |
| 16 | |
| 17 | template <class E> |
Kaelyn Uhrain | 257e17f | 2011-10-11 17:17:40 +0000 | [diff] [blame] | 18 | error_condition(E _e) { |
| 19 | // make_error_condition must not be typo corrected to error_condition |
| 20 | // even though the first declaration of make_error_condition has not |
| 21 | // yet been encountered. This was a bug in the first version of the type |
| 22 | // name typo correction patch that wasn't noticed until building LLVM with |
| 23 | // Clang failed. |
| 24 | *this = make_error_condition(_e); |
| 25 | } |
Kaelyn Uhrain | fac9467 | 2011-10-11 01:02:41 +0000 | [diff] [blame] | 26 | |
| 27 | }; |
| 28 | |
| 29 | inline error_condition make_error_condition(errc _e) { |
| 30 | return error_condition(static_cast<int>(_e)); |
| 31 | } |
Kaelyn Uhrain | 7d5e694 | 2012-01-11 19:37:46 +0000 | [diff] [blame] | 32 | |
| 33 | |
| 34 | // Prior to the introduction of a callback object to further filter possible |
| 35 | // typo corrections, this example would not trigger a suggestion as "base_type" |
| 36 | // is a closer match to "basetype" than is "BaseType" but "base_type" does not |
| 37 | // refer to a base class or non-static data member. |
| 38 | struct BaseType { }; |
| 39 | struct Derived : public BaseType { // expected-note {{base class 'BaseType' specified here}} |
Kaelyn Uhrain | e4c7f90 | 2012-01-13 21:28:55 +0000 | [diff] [blame] | 40 | static int base_type; // expected-note {{'base_type' declared here}} |
Kaelyn Uhrain | 7d5e694 | 2012-01-11 19:37:46 +0000 | [diff] [blame] | 41 | Derived() : basetype() {} // expected-error{{initializer 'basetype' does not name a non-static data member or base class; did you mean the base class 'BaseType'?}} |
| 42 | }; |
Kaelyn Uhrain | dc98cd0 | 2012-01-11 21:17:51 +0000 | [diff] [blame] | 43 | |
Kaelyn Uhrain | f8ec8c9 | 2012-01-13 23:10:36 +0000 | [diff] [blame] | 44 | // Test the improvement from passing a callback object to CorrectTypo in |
| 45 | // the helper function LookupMemberExprInRecord. |
Kaelyn Uhrain | e4c7f90 | 2012-01-13 21:28:55 +0000 | [diff] [blame] | 46 | int get_type(struct Derived *st) { |
| 47 | return st->Base_Type; // expected-error{{no member named 'Base_Type' in 'Derived'; did you mean 'base_type'?}} |
| 48 | } |
| 49 | |
Kaelyn Uhrain | dc98cd0 | 2012-01-11 21:17:51 +0000 | [diff] [blame] | 50 | // In this example, somename should not be corrected to the cached correction |
| 51 | // "some_name" since "some_name" is a class and a namespace name is needed. |
| 52 | class some_name {}; // expected-note {{'some_name' declared here}} |
| 53 | somename Foo; // expected-error {{unknown type name 'somename'; did you mean 'some_name'?}} |
| 54 | namespace SomeName {} // expected-note {{namespace 'SomeName' defined here}} |
| 55 | using namespace somename; // expected-error {{no namespace named 'somename'; did you mean 'SomeName'?}} |
Kaelyn Uhrain | 425d631 | 2012-01-12 19:27:05 +0000 | [diff] [blame] | 56 | |
| 57 | |
| 58 | // Without the callback object, CorrectTypo would choose "field1" as the |
| 59 | // correction for "fielda" as it is closer than "FieldA", but that correction |
| 60 | // would be later discarded by the caller and no suggestion would be given. |
| 61 | struct st { |
| 62 | struct { |
| 63 | int field1; |
| 64 | }; |
| 65 | double FieldA; // expected-note{{'FieldA' declared here}} |
| 66 | }; |
| 67 | st var = { .fielda = 0.0 }; // expected-error{{field designator 'fielda' does not refer to any field in type 'st'; did you mean 'FieldA'?}} |
Kaelyn Uhrain | 3b4b047 | 2012-01-12 22:32:39 +0000 | [diff] [blame] | 68 | |
Kaelyn Uhrain | f8ec8c9 | 2012-01-13 23:10:36 +0000 | [diff] [blame] | 69 | // Test the improvement from passing a callback object to CorrectTypo in |
Kaelyn Uhrain | 43e875d | 2012-01-18 21:41:41 +0000 | [diff] [blame] | 70 | // Sema::BuildCXXNestedNameSpecifier. And also for the improvement by doing |
| 71 | // so in Sema::getTypeName. |
| 72 | typedef char* another_str; // expected-note{{'another_str' declared here}} |
Kaelyn Uhrain | 3b4b047 | 2012-01-12 22:32:39 +0000 | [diff] [blame] | 73 | namespace AnotherStd { // expected-note{{'AnotherStd' declared here}} |
| 74 | class string {}; |
| 75 | } |
| 76 | another_std::string str; // expected-error{{use of undeclared identifier 'another_std'; did you mean 'AnotherStd'?}} |
Kaelyn Uhrain | 43e875d | 2012-01-18 21:41:41 +0000 | [diff] [blame] | 77 | another_str *cstr = new AnotherStr; // expected-error{{unknown type name 'AnotherStr'; did you mean 'another_str'?}} |
Kaelyn Uhrain | f8ec8c9 | 2012-01-13 23:10:36 +0000 | [diff] [blame] | 78 | |
| 79 | // Test the improvement from passing a callback object to CorrectTypo in |
| 80 | // Sema::ActOnSizeofParameterPackExpr. |
| 81 | char* TireNames; |
| 82 | template<typename ...TypeNames> struct count { // expected-note{{parameter pack 'TypeNames' declared here}} |
| 83 | static const unsigned value = sizeof...(TyreNames); // expected-error{{'TyreNames' does not refer to the name of a parameter pack; did you mean 'TypeNames'?}} |
| 84 | }; |
Kaelyn Uhrain | 43e875d | 2012-01-18 21:41:41 +0000 | [diff] [blame] | 85 | |
| 86 | // Test the typo-correction callback in Sema::DiagnoseUnknownTypeName. |
| 87 | namespace unknown_type_test { |
Kaelyn Uhrain | 438ee1f | 2012-01-23 20:18:59 +0000 | [diff] [blame] | 88 | class StreamOut {}; // expected-note 2 {{'StreamOut' declared here}} |
| 89 | long stream_count; // expected-note 2 {{'stream_count' declared here}} |
Kaelyn Uhrain | 43e875d | 2012-01-18 21:41:41 +0000 | [diff] [blame] | 90 | }; |
| 91 | unknown_type_test::stream_out out; // expected-error{{no type named 'stream_out' in namespace 'unknown_type_test'; did you mean 'StreamOut'?}} |
| 92 | |
Kaelyn Uhrain | 438ee1f | 2012-01-23 20:18:59 +0000 | [diff] [blame] | 93 | // Demonstrate a case where using only the cached value returns the wrong thing |
| 94 | // when the cached value was the result of a previous callback object that only |
| 95 | // accepts a subset of the current callback object. |
| 96 | namespace { |
| 97 | using namespace unknown_type_test; |
| 98 | void bar(long i); |
| 99 | void before_caching_classname() { |
| 100 | bar((stream_out)); // expected-error{{use of undeclared identifier 'stream_out'; did you mean 'stream_count'?}} |
| 101 | } |
| 102 | stream_out out; // expected-error{{unknown type name 'stream_out'; did you mean 'StreamOut'?}} |
| 103 | void after_caching_classname() { |
| 104 | bar((stream_out)); // expected-error{{use of undeclared identifier 'stream_out'; did you mean 'stream_count'?}} |
| 105 | } |
| 106 | } |
| 107 | |
Kaelyn Uhrain | 43e875d | 2012-01-18 21:41:41 +0000 | [diff] [blame] | 108 | // Test the typo-correction callback in Sema::DiagnoseInvalidRedeclaration. |
| 109 | struct BaseDecl { |
| 110 | void add_in(int i); |
| 111 | }; |
| 112 | struct TestRedecl : public BaseDecl { |
| 113 | void add_it(int i); // expected-note{{'add_it' declared here}} |
| 114 | }; |
| 115 | void TestRedecl::add_in(int i) {} // expected-error{{out-of-line definition of 'add_in' does not match any declaration in 'TestRedecl'; did you mean 'add_it'?}} |
Kaelyn Uhrain | 60a09dc | 2012-01-25 18:37:44 +0000 | [diff] [blame] | 116 | |
Kaelyn Uhrain | cd78e61 | 2012-01-25 20:49:08 +0000 | [diff] [blame] | 117 | // Test the improved typo correction for the Parser::ParseCastExpr => |
| 118 | // Sema::ActOnIdExpression => Sema::DiagnoseEmptyLookup call path. |
Richard Smith | 0576681 | 2012-08-18 00:55:03 +0000 | [diff] [blame] | 119 | class SomeNetMessage; // expected-note 2{{'SomeNetMessage'}} |
Kaelyn Uhrain | cd78e61 | 2012-01-25 20:49:08 +0000 | [diff] [blame] | 120 | class Message {}; |
| 121 | void foo(Message&); |
| 122 | void foo(SomeNetMessage&); |
| 123 | void doit(void *data) { |
| 124 | Message somenetmsg; // expected-note{{'somenetmsg' declared here}} |
| 125 | foo(somenetmessage); // expected-error{{use of undeclared identifier 'somenetmessage'; did you mean 'somenetmsg'?}} |
Richard Smith | 0576681 | 2012-08-18 00:55:03 +0000 | [diff] [blame] | 126 | foo((somenetmessage)data); // expected-error{{unknown type name 'somenetmessage'; did you mean 'SomeNetMessage'?}} expected-error{{incomplete type}} |
Kaelyn Uhrain | cd78e61 | 2012-01-25 20:49:08 +0000 | [diff] [blame] | 127 | } |
| 128 | |
Kaelyn Uhrain | 60a09dc | 2012-01-25 18:37:44 +0000 | [diff] [blame] | 129 | // Test the typo-correction callback in BuildRecoveryCallExpr. |
| 130 | // Solves the main issue in PR 9320 of suggesting corrections that take the |
| 131 | // wrong number of arguments. |
| 132 | void revoke(const char*); // expected-note 2{{'revoke' declared here}} |
| 133 | void Test() { |
| 134 | Invoke(); // expected-error{{use of undeclared identifier 'Invoke'}} |
| 135 | Invoke("foo"); // expected-error{{use of undeclared identifier 'Invoke'; did you mean 'revoke'?}} |
| 136 | Invoke("foo", "bar"); // expected-error{{use of undeclared identifier 'Invoke'}} |
| 137 | } |
| 138 | void Test2(void (*invoke)(const char *, int)) { // expected-note{{'invoke' declared here}} |
| 139 | Invoke(); // expected-error{{use of undeclared identifier 'Invoke'}} |
| 140 | Invoke("foo"); // expected-error{{use of undeclared identifier 'Invoke'; did you mean 'revoke'?}} |
| 141 | Invoke("foo", 7); // expected-error{{use of undeclared identifier 'Invoke'; did you mean 'invoke'?}} |
| 142 | Invoke("foo", 7, 22); // expected-error{{use of undeclared identifier 'Invoke'}} |
| 143 | } |
| 144 | |
| 145 | void provoke(const char *x, bool y=false) {} // expected-note 2{{'provoke' declared here}} |
| 146 | void Test3() { |
| 147 | Provoke(); // expected-error{{use of undeclared identifier 'Provoke'}} |
| 148 | Provoke("foo"); // expected-error{{use of undeclared identifier 'Provoke'; did you mean 'provoke'?}} |
| 149 | Provoke("foo", true); // expected-error{{use of undeclared identifier 'Provoke'; did you mean 'provoke'?}} |
| 150 | Provoke("foo", 7, 22); // expected-error{{use of undeclared identifier 'Provoke'}} |
| 151 | } |
Kaelyn Uhrain | 3943b1c | 2012-01-25 21:11:35 +0000 | [diff] [blame] | 152 | |
| 153 | // PR 11737 - Don't try to typo-correct the implicit 'begin' and 'end' in a |
| 154 | // C++11 for-range statement. |
| 155 | struct R {}; |
| 156 | bool begun(R); |
| 157 | void RangeTest() { |
Sam Panzer | e1715b6 | 2012-08-21 00:52:01 +0000 | [diff] [blame] | 158 | for (auto b : R()) {} // expected-error {{invalid range expression of type 'R'}} |
Kaelyn Uhrain | 3943b1c | 2012-01-25 21:11:35 +0000 | [diff] [blame] | 159 | } |
Kaelyn Uhrain | 3336353 | 2012-02-16 22:40:59 +0000 | [diff] [blame] | 160 | |
| 161 | // PR 12019 - Avoid infinite mutual recursion in DiagnoseInvalidRedeclaration |
| 162 | // by not trying to typo-correct a method redeclaration to declarations not |
| 163 | // in the current record. |
| 164 | class Parent { |
| 165 | void set_types(int index, int value); |
| 166 | void add_types(int value); |
| 167 | }; |
| 168 | class Child: public Parent {}; |
| 169 | void Child::add_types(int value) {} // expected-error{{out-of-line definition of 'add_types' does not match any declaration in 'Child'}} |
Kaelyn Uhrain | e43fe99 | 2012-02-22 01:03:07 +0000 | [diff] [blame] | 170 | |
| 171 | // Fix the callback based filtering of typo corrections within |
| 172 | // Sema::ActOnIdExpression by Parser::ParseCastExpression to allow type names as |
| 173 | // potential corrections for template arguments. |
| 174 | namespace clash { |
Richard Smith | 0576681 | 2012-08-18 00:55:03 +0000 | [diff] [blame] | 175 | class ConstructExpr {}; // expected-note 2{{'clash::ConstructExpr' declared here}} |
Kaelyn Uhrain | e43fe99 | 2012-02-22 01:03:07 +0000 | [diff] [blame] | 176 | } |
| 177 | class ClashTool { |
| 178 | bool HaveConstructExpr(); |
| 179 | template <class T> T* getExprAs(); |
| 180 | |
| 181 | void test() { |
| 182 | ConstructExpr *expr = // expected-error{{unknown type name 'ConstructExpr'; did you mean 'clash::ConstructExpr'?}} |
Richard Smith | 0576681 | 2012-08-18 00:55:03 +0000 | [diff] [blame] | 183 | getExprAs<ConstructExpr>(); // expected-error{{unknown type name 'ConstructExpr'; did you mean 'clash::ConstructExpr'?}} |
Kaelyn Uhrain | e43fe99 | 2012-02-22 01:03:07 +0000 | [diff] [blame] | 184 | } |
| 185 | }; |
Nick Lewycky | 173a37a | 2012-04-03 21:44:08 +0000 | [diff] [blame] | 186 | |
| 187 | namespace test1 { |
| 188 | struct S { |
| 189 | struct Foobar *f; // expected-note{{'Foobar' declared here}} |
| 190 | }; |
| 191 | test1::FooBar *b; // expected-error{{no type named 'FooBar' in namespace 'test1'; did you mean 'Foobar'?}} |
| 192 | } |
Richard Smith | 827adaf | 2012-05-15 21:01:51 +0000 | [diff] [blame] | 193 | |
| 194 | namespace ImplicitInt { |
| 195 | void f(int, unsinged); // expected-error{{did you mean 'unsigned'}} |
| 196 | struct S { |
| 197 | unsinged : 4; // expected-error{{did you mean 'unsigned'}} |
| 198 | }; |
| 199 | } |
Kaelyn Uhrain | 784ae8e | 2012-06-01 18:11:16 +0000 | [diff] [blame] | 200 | |
| 201 | namespace PR12951 { |
| 202 | // If there are two corrections that have the same identifier and edit distance |
| 203 | // and only differ by their namespaces, don't suggest either as a correction |
| 204 | // since both are equally likely corrections. |
| 205 | namespace foobar { struct Thing {}; } |
| 206 | namespace bazquux { struct Thing {}; } |
| 207 | void f() { Thing t; } // expected-error{{unknown type name 'Thing'}} |
| 208 | } |
Richard Smith | 0f4b5be | 2012-06-08 21:35:42 +0000 | [diff] [blame] | 209 | |
| 210 | namespace PR13051 { |
| 211 | template<typename T> struct S { |
| 212 | template<typename U> void f(); |
| 213 | operator bool() const; |
| 214 | }; |
| 215 | |
| 216 | void f() { |
| 217 | f(&S<int>::tempalte f<int>); // expected-error{{did you mean 'template'?}} |
| 218 | f(&S<int>::opeartor bool); // expected-error{{did you mean 'operator'?}} |
| 219 | f(&S<int>::foo); // expected-error-re{{no member named 'foo' in 'PR13051::S<int>'$}} |
| 220 | } |
| 221 | } |
Kaelyn Uhrain | c1fb542 | 2012-06-22 23:37:05 +0000 | [diff] [blame] | 222 | |
Richard Smith | 0576681 | 2012-08-18 00:55:03 +0000 | [diff] [blame] | 223 | inf f(doulbe); // expected-error{{'int'}} expected-error{{'double'}} |
| 224 | |
Kaelyn Uhrain | c1fb542 | 2012-06-22 23:37:05 +0000 | [diff] [blame] | 225 | namespace PR6325 { |
| 226 | class foo { }; // expected-note{{'foo' declared here}} |
| 227 | // Note that for this example (pulled from the PR), if keywords are not excluded |
| 228 | // as correction candidates then no suggestion would be given; correcting |
| 229 | // 'boo' to 'bool' is the same edit distance as correcting 'boo' to 'foo'. |
| 230 | class bar : boo { }; // expected-error{{unknown class name 'boo'; did you mean 'foo'?}} |
| 231 | } |
Kaelyn Uhrain | 4ac5751 | 2012-06-29 21:30:39 +0000 | [diff] [blame] | 232 | |
| 233 | namespace bogus_keyword_suggestion { |
| 234 | void test() { |
| 235 | status = "OK"; // expected-error-re{{use of undeclared identifier 'status'$}} |
| 236 | return status; // expected-error-re{{use of undeclared identifier 'status'$}} |
| 237 | } |
| 238 | } |
Kaelyn Uhrain | 728948f | 2012-11-19 18:49:53 +0000 | [diff] [blame] | 239 | |
| 240 | namespace PR13387 { |
| 241 | struct A { |
Nick Lewycky | d9de51f | 2013-05-07 22:14:37 +0000 | [diff] [blame] | 242 | void CreateFoo(float, float); |
Kaelyn Uhrain | 728948f | 2012-11-19 18:49:53 +0000 | [diff] [blame] | 243 | void CreateBar(float, float); |
| 244 | }; |
| 245 | struct B : A { |
| 246 | using A::CreateFoo; |
| 247 | void CreateFoo(int, int); |
| 248 | }; |
| 249 | void f(B &x) { |
| 250 | x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}} |
| 251 | } |
| 252 | } |
Kaelyn Uhrain | 20a7cf4 | 2013-04-03 16:59:49 +0000 | [diff] [blame] | 253 | |
| 254 | struct DataStruct {void foo();}; |
| 255 | struct T { |
| 256 | DataStruct data_struct; |
| 257 | void f(); |
| 258 | }; |
| 259 | // should be void T::f(); |
| 260 | void f() { |
| 261 | data_struct->foo(); // expected-error-re{{use of undeclared identifier 'data_struct'$}} |
| 262 | } |
Nick Lewycky | d9de51f | 2013-05-07 22:14:37 +0000 | [diff] [blame] | 263 | |
| 264 | namespace b6956809_test1 { |
| 265 | struct A {}; |
| 266 | struct B {}; |
| 267 | |
| 268 | struct S1 { |
| 269 | void method(A*); // no note here |
| 270 | void method(B*); |
| 271 | }; |
| 272 | |
| 273 | void test1() { |
| 274 | B b; |
| 275 | S1 s; |
| 276 | s.methodd(&b); // expected-error{{no member named 'methodd' in 'b6956809_test1::S1'; did you mean 'method'}} |
| 277 | } |
| 278 | |
| 279 | struct S2 { |
| 280 | S2(); |
| 281 | void method(A*) const; // expected-note{{candidate function not viable}} |
| 282 | private: |
| 283 | void method(B*); // expected-note{{candidate function not viable}} |
| 284 | }; |
| 285 | |
| 286 | void test2() { |
| 287 | B b; |
| 288 | const S2 s; |
| 289 | s.methodd(&b); // expected-error{{no member named 'methodd' in 'b6956809_test1::S2'; did you mean 'method'}} expected-error{{no matching member function for call to 'method'}} |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | namespace b6956809_test2 { |
| 294 | template<typename T> struct Err { typename T::error n; }; // expected-error{{type 'void *' cannot be used prior to '::' because it has no members}} |
| 295 | struct S { |
| 296 | template<typename T> typename Err<T>::type method(T); // expected-note{{in instantiation of template class 'b6956809_test2::Err<void *>' requested here}} expected-note{{while substituting deduced template arguments into function template 'method' [with T = void *]}} |
| 297 | template<typename T> int method(T *); |
| 298 | }; |
| 299 | |
| 300 | void test() { |
| 301 | S s; |
| 302 | int k = s.methodd((void*)0); // expected-error{{no member named 'methodd' in 'b6956809_test2::S'; did you mean 'method'?}} |
| 303 | } |
| 304 | } |