]> granicus.if.org Git - clang/commitdiff
Filter out non-static class members when correcting non-member-references.
authorKaelyn Takata <rikka@google.com>
Wed, 5 Nov 2014 00:09:29 +0000 (00:09 +0000)
committerKaelyn Takata <rikka@google.com>
Wed, 5 Nov 2014 00:09:29 +0000 (00:09 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@221319 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Parse/ParseTentative.cpp
test/SemaCXX/typo-correction-pt2.cpp

index 4b1375dfc18df7553cbfd4f8e3851546ba9fc61d..944e88722f58faa32921bc534ac28e328b08fc1b 100644 (file)
@@ -1006,6 +1006,28 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) {
       != TentativelyDeclaredIdentifiers.end();
 }
 
+namespace {
+class TentativeParseCCC : public CorrectionCandidateCallback {
+public:
+  TentativeParseCCC(const Token &Next) {
+    WantRemainingKeywords = false;
+    WantTypeSpecifiers = Next.is(tok::l_paren) || Next.is(tok::r_paren) ||
+                         Next.is(tok::greater) || Next.is(tok::l_brace) ||
+                         Next.is(tok::identifier);
+  }
+
+  bool ValidateCandidate(const TypoCorrection &Candidate) override {
+    // Reject any candidate that only resolves to instance members since they
+    // aren't viable as standalone identifiers instead of member references.
+    if (Candidate.isResolved() && !Candidate.isKeyword() &&
+        std::all_of(Candidate.begin(), Candidate.end(),
+                    [](NamedDecl *ND) { return ND->isCXXInstanceMember(); }))
+      return false;
+
+    return CorrectionCandidateCallback::ValidateCandidate(Candidate);
+  }
+};
+}
 /// isCXXDeclarationSpecifier - Returns TPResult::True if it is a declaration
 /// specifier, TPResult::False if it is not, TPResult::Ambiguous if it could
 /// be either a decl-specifier or a function-style cast, and TPResult::Error
@@ -1131,14 +1153,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
       // a parse error one way or another. In that case, tell the caller that
       // this is ambiguous. Typo-correct to type and expression keywords and
       // to types and identifiers, in order to try to recover from errors.
-      auto TypoCorrection = llvm::make_unique<CorrectionCandidateCallback>();
-      TypoCorrection->WantRemainingKeywords = false;
-      TypoCorrection->WantTypeSpecifiers =
-          Next.is(tok::l_paren) || Next.is(tok::r_paren) ||
-          Next.is(tok::greater) || Next.is(tok::l_brace) ||
-          Next.is(tok::identifier);
       switch (TryAnnotateName(false /* no nested name specifier */,
-                              std::move(TypoCorrection))) {
+                              llvm::make_unique<TentativeParseCCC>(Next))) {
       case ANK_Error:
         return TPResult::Error;
       case ANK_TentativeDecl:
index de12da77d1a4f847aad426f3a46225d7ffb851d6..5d3f1236ac26dd8e2580c31b39cc243da06625d9 100644 (file)
@@ -319,3 +319,16 @@ int bar() {
   Test::SomeSettings some_settings; // expected-error {{no type named 'SomeSettings' in 'testCXXDeclarationSpecifierParsing::Test'; did you mean 'test::SomeSettings'?}}
 }
 }
+
+namespace testNonStaticMemberHandling {
+struct Foo {
+  bool usesMetadata;  // expected-note {{'usesMetadata' declared here}}
+};
+int test(Foo f) {
+  if (UsesMetadata)  // expected-error-re {{use of undeclared identifier 'UsesMetadata'{{$}}}}
+    return 5;
+  if (f.UsesMetadata)  // expected-error {{no member named 'UsesMetadata' in 'testNonStaticMemberHandling::Foo'; did you mean 'usesMetadata'?}}
+    return 11;
+  return 0;
+}
+};