]> granicus.if.org Git - clang/commitdiff
Be smarter about deciding to add a leading '::' to a
authorKaelyn Uhrain <rikka@google.com>
Sat, 19 Oct 2013 00:04:52 +0000 (00:04 +0000)
committerKaelyn Uhrain <rikka@google.com>
Sat, 19 Oct 2013 00:04:52 +0000 (00:04 +0000)
NestedNameSpecifier that replaces an existing specifier.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193019 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaLookup.cpp
test/SemaCXX/qualified-id-lookup.cpp
test/SemaCXX/using-decl-1.cpp

index 2383b4d25b6a1439a3e86be048ce7ff47fb64a9a..bb1150fc72a4659b1a440f80ecde1cbac24435a9 100644 (file)
@@ -3575,6 +3575,7 @@ typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList;
 class NamespaceSpecifierSet {
   ASTContext &Context;
   DeclContextList CurContextChain;
+  std::string CurNameSpecifier;
   SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers;
   SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers;
   bool isSorted;
@@ -3594,9 +3595,13 @@ class NamespaceSpecifierSet {
                         CXXScopeSpec *CurScopeSpec)
       : Context(Context), CurContextChain(BuildContextChain(CurContext)),
         isSorted(false) {
-    if (CurScopeSpec && CurScopeSpec->getScopeRep())
-      getNestedNameSpecifierIdentifiers(CurScopeSpec->getScopeRep(),
-                                        CurNameSpecifierIdentifiers);
+    if (NestedNameSpecifier *NNS =
+            CurScopeSpec ? CurScopeSpec->getScopeRep() : 0) {
+      llvm::raw_string_ostream SpecifierOStream(CurNameSpecifier);
+      NNS->print(SpecifierOStream, Context.getPrintingPolicy());
+
+      getNestedNameSpecifierIdentifiers(NNS, CurNameSpecifierIdentifiers);
+    }
     // Build the list of identifiers that would be used for an absolute
     // (from the global context) NestedNameSpecifier referring to the current
     // context.
@@ -3659,6 +3664,25 @@ void NamespaceSpecifierSet::SortNamespaces() {
   isSorted = true;
 }
 
+static unsigned BuildNestedNameSpecifier(ASTContext &Context,
+                                         DeclContextList &DeclChain,
+                                         NestedNameSpecifier *&NNS) {
+  unsigned NumSpecifiers = 0;
+  for (DeclContextList::reverse_iterator C = DeclChain.rbegin(),
+                                      CEnd = DeclChain.rend();
+       C != CEnd; ++C) {
+    if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C)) {
+      NNS = NestedNameSpecifier::Create(Context, NNS, ND);
+      ++NumSpecifiers;
+    } else if (RecordDecl *RD = dyn_cast_or_null<RecordDecl>(*C)) {
+      NNS = NestedNameSpecifier::Create(Context, NNS, RD->isTemplateDecl(),
+                                        RD->getTypeForDecl());
+      ++NumSpecifiers;
+    }
+  }
+  return NumSpecifiers;
+}
+
 void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) {
   NestedNameSpecifier *NNS = NULL;
   unsigned NumSpecifiers = 0;
@@ -3673,34 +3697,37 @@ void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) {
     NamespaceDeclChain.pop_back();
   }
 
+  // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain
+  NumSpecifiers = BuildNestedNameSpecifier(Context, NamespaceDeclChain, NNS);
+
   // Add an explicit leading '::' specifier if needed.
   if (NamespaceDeclChain.empty()) {
-    NamespaceDeclChain = FullNamespaceDeclChain;
+    // Rebuild the NestedNameSpecifier as a globally-qualified specifier.
     NNS = NestedNameSpecifier::GlobalSpecifier(Context);
+    NumSpecifiers =
+        BuildNestedNameSpecifier(Context, FullNamespaceDeclChain, NNS);
   } else if (NamedDecl *ND =
                  dyn_cast_or_null<NamedDecl>(NamespaceDeclChain.back())) {
     IdentifierInfo *Name = ND->getIdentifier();
-    if (std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(),
-                  Name) != CurContextIdentifiers.end() ||
-        std::find(CurNameSpecifierIdentifiers.begin(),
+    bool SameNameSpecifier = false;
+    if (std::find(CurNameSpecifierIdentifiers.begin(),
                   CurNameSpecifierIdentifiers.end(),
                   Name) != CurNameSpecifierIdentifiers.end()) {
-      NamespaceDeclChain = FullNamespaceDeclChain;
-      NNS = NestedNameSpecifier::GlobalSpecifier(Context);
+      std::string NewNameSpecifier;
+      llvm::raw_string_ostream SpecifierOStream(NewNameSpecifier);
+      SmallVector<const IdentifierInfo *, 4> NewNameSpecifierIdentifiers;
+      getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers);
+      NNS->print(SpecifierOStream, Context.getPrintingPolicy());
+      SpecifierOStream.flush();
+      SameNameSpecifier = NewNameSpecifier == CurNameSpecifier;
     }
-  }
-
-  // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain
-  for (DeclContextList::reverse_iterator C = NamespaceDeclChain.rbegin(),
-                                      CEnd = NamespaceDeclChain.rend();
-       C != CEnd; ++C) {
-    if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C)) {
-      NNS = NestedNameSpecifier::Create(Context, NNS, ND);
-      ++NumSpecifiers;
-    } else if (RecordDecl *RD = dyn_cast_or_null<RecordDecl>(*C)) {
-      NNS = NestedNameSpecifier::Create(Context, NNS, RD->isTemplateDecl(),
-                                        RD->getTypeForDecl());
-      ++NumSpecifiers;
+    if (SameNameSpecifier ||
+        std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(),
+                  Name) != CurContextIdentifiers.end()) {
+      // Rebuild the NestedNameSpecifier as a globally-qualified specifier.
+      NNS = NestedNameSpecifier::GlobalSpecifier(Context);
+      NumSpecifiers =
+          BuildNestedNameSpecifier(Context, FullNamespaceDeclChain, NNS);
     }
   }
 
index 26f1d7c472fd9f1948cf7ad32b0c0bd52d474b99..23164fa42f32561380ce93f8a9a9410e026ce584 100644 (file)
@@ -86,13 +86,13 @@ namespace a {
 namespace a {  
   namespace a {   // A1
     namespace a { // A2
-      int i; // expected-note{{'::a::a::a::i' declared here}}
+      int i; // expected-note{{'a::a::a::i' declared here}}
     }
   }
 }
 
 void test_a() {
-  a::a::i = 3; // expected-error{{no member named 'i' in namespace 'a::a'; did you mean '::a::a::a::i'?}}
+  a::a::i = 3; // expected-error{{no member named 'i' in namespace 'a::a'; did you mean 'a::a::a::i'?}}
   a::a::a::i = 4;
   a::a::j = 3; // expected-error-re{{no member named 'j' in namespace 'a::a'$}}
 }
index 41710cc9090083f4cbfd958ba1dc1fb319e5c08e..24d92f175c302d271df2a19869f4f1e69fdc17d3 100644 (file)
@@ -139,24 +139,24 @@ using typename N::FFG; // expected-error {{no member named 'FFG' in namespace 'u
 // Currently hints aren't provided to drop out the incorrect M::.
 namespace using_suggestion_ty_dropped_nested_specifier {
 namespace N {
-class AAA {};
+class AAA {}; // expected-note {{'N::AAA' declared here}}
 namespace M { }
 }
-using N::M::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_ty_dropped_nested_specifier::N::M'}}
+using N::M::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_ty_dropped_nested_specifier::N::M'; did you mean 'N::AAA'?}}
 }
 
 namespace using_suggestion_tyname_ty_dropped_nested_specifier {
 namespace N {
-class AAA {};
+class AAA {}; // expected-note {{'N::AAA' declared here}}
 namespace M { }
 }
-using typename N::M::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_tyname_ty_dropped_nested_specifier::N::M'}}
+using typename N::M::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_tyname_ty_dropped_nested_specifier::N::M'; did you mean 'N::AAA'?}}
 }
 
 namespace using_suggestion_val_dropped_nested_specifier {
 namespace N {
-void FFF() {}
+void FFF() {} // expected-note {{'N::FFF' declared here}}
 namespace M { }
 }
-using N::M::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_nested_specifier::N::M'}}
+using N::M::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_nested_specifier::N::M'; did you mean 'N::FFF'?}}
 }