1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/Tooling/Core/Lookup.h" |
14 | #include "clang/AST/Decl.h" |
15 | #include "clang/AST/DeclCXX.h" |
16 | #include "clang/AST/DeclarationName.h" |
17 | #include "llvm/ADT/SmallVector.h" |
18 | using namespace clang; |
19 | using namespace clang::tooling; |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | static llvm::SmallVector<const NamespaceDecl *, 4> |
27 | getAllNamedNamespaces(const DeclContext *Context) { |
28 | llvm::SmallVector<const NamespaceDecl *, 4> Namespaces; |
29 | auto GetNextNamedNamespace = [](const DeclContext *Context) { |
30 | |
31 | while (Context && (!isa<NamespaceDecl>(Context) || |
32 | cast<NamespaceDecl>(Context)->isAnonymousNamespace())) |
33 | Context = Context->getParent(); |
34 | return Context; |
35 | }; |
36 | for (Context = GetNextNamedNamespace(Context); Context != nullptr; |
37 | Context = GetNextNamedNamespace(Context->getParent())) |
38 | Namespaces.push_back(cast<NamespaceDecl>(Context)); |
39 | return Namespaces; |
40 | } |
41 | |
42 | |
43 | |
44 | |
45 | static bool |
46 | usingFromDifferentCanonicalNamespace(const DeclContext *FromContext, |
47 | const DeclContext *UseContext) { |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | llvm::SmallVector<const NamespaceDecl *, 4> FromNamespaces = |
54 | getAllNamedNamespaces(FromContext); |
55 | llvm::SmallVector<const NamespaceDecl *, 4> UseNamespaces = |
56 | getAllNamedNamespaces(UseContext); |
57 | |
58 | |
59 | if (UseNamespaces.size() < FromNamespaces.size()) |
60 | return false; |
61 | unsigned Diff = UseNamespaces.size() - FromNamespaces.size(); |
62 | auto FromIter = FromNamespaces.begin(); |
63 | |
64 | |
65 | |
66 | auto UseIter = UseNamespaces.begin() + Diff; |
67 | for (; FromIter != FromNamespaces.end() && UseIter != UseNamespaces.end(); |
68 | ++FromIter, ++UseIter) { |
69 | |
70 | if (*FromIter == *UseIter) |
71 | return false; |
72 | |
73 | |
74 | if (cast<NamespaceDecl>(*FromIter)->getDeclName() == |
75 | cast<NamespaceDecl>(*UseIter)->getDeclName()) |
76 | return true; |
77 | } |
78 | assert(FromIter == FromNamespaces.end() && UseIter == UseNamespaces.end()); |
79 | return false; |
80 | } |
81 | |
82 | static StringRef getBestNamespaceSubstr(const DeclContext *DeclA, |
83 | StringRef NewName, |
84 | bool HadLeadingColonColon) { |
85 | while (true) { |
86 | while (DeclA && !isa<NamespaceDecl>(DeclA)) |
87 | DeclA = DeclA->getParent(); |
88 | |
89 | |
90 | if (!DeclA) |
91 | return HadLeadingColonColon ? NewName : NewName.substr(2); |
92 | |
93 | |
94 | |
95 | |
96 | std::string NS = |
97 | "::" + cast<NamespaceDecl>(DeclA)->getQualifiedNameAsString() + "::"; |
98 | if (NewName.startswith(NS)) |
99 | return NewName.substr(NS.size()); |
100 | |
101 | |
102 | |
103 | |
104 | DeclA = DeclA->getParent(); |
105 | } |
106 | } |
107 | |
108 | |
109 | static bool isFullyQualified(const NestedNameSpecifier *NNS) { |
110 | while (NNS) { |
111 | if (NNS->getKind() == NestedNameSpecifier::Global) |
112 | return true; |
113 | NNS = NNS->getPrefix(); |
114 | } |
115 | return false; |
116 | } |
117 | |
118 | |
119 | |
120 | |
121 | |
122 | |
123 | |
124 | static std::string disambiguateSpellingInScope(StringRef Spelling, |
125 | StringRef QName, |
126 | const DeclContext &UseContext) { |
127 | (0) . __assert_fail ("QName.startswith(\"..\")", "/home/seafit/code_projects/clang_source/clang/lib/Tooling/Core/Lookup.cpp", 127, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(QName.startswith("::")); |
128 | assert(QName.endswith(Spelling)); |
129 | if (Spelling.startswith("::")) |
130 | return Spelling; |
131 | |
132 | auto UnspelledSpecifier = QName.drop_back(Spelling.size()); |
133 | llvm::SmallVector<llvm::StringRef, 2> UnspelledScopes; |
134 | UnspelledSpecifier.split(UnspelledScopes, "::", -1, |
135 | ); |
136 | |
137 | llvm::SmallVector<const NamespaceDecl *, 4> EnclosingNamespaces = |
138 | getAllNamedNamespaces(&UseContext); |
139 | auto &AST = UseContext.getParentASTContext(); |
140 | StringRef TrimmedQName = QName.substr(2); |
141 | |
142 | auto IsAmbiguousSpelling = [&EnclosingNamespaces, &AST, &TrimmedQName]( |
143 | const llvm::StringRef CurSpelling) { |
144 | if (CurSpelling.startswith("::")) |
145 | return false; |
146 | |
147 | |
148 | |
149 | StringRef Head = CurSpelling.split("::").first; |
150 | for (const auto *NS : EnclosingNamespaces) { |
151 | auto LookupRes = NS->lookup(DeclarationName(&AST.Idents.get(Head))); |
152 | if (!LookupRes.empty()) { |
153 | for (const NamedDecl *Res : LookupRes) |
154 | if (!TrimmedQName.startswith(Res->getQualifiedNameAsString())) |
155 | return true; |
156 | } |
157 | } |
158 | return false; |
159 | }; |
160 | |
161 | |
162 | std::string Disambiguated = Spelling; |
163 | while (IsAmbiguousSpelling(Disambiguated)) { |
164 | if (UnspelledScopes.empty()) { |
165 | Disambiguated = "::" + Disambiguated; |
166 | } else { |
167 | Disambiguated = (UnspelledScopes.back() + "::" + Disambiguated).str(); |
168 | UnspelledScopes.pop_back(); |
169 | } |
170 | } |
171 | return Disambiguated; |
172 | } |
173 | |
174 | std::string tooling::replaceNestedName(const NestedNameSpecifier *Use, |
175 | const DeclContext *UseContext, |
176 | const NamedDecl *FromDecl, |
177 | StringRef ReplacementString) { |
178 | (0) . __assert_fail ("ReplacementString.startswith(\"..\") && \"Expected fully-qualified name!\"", "/home/seafit/code_projects/clang_source/clang/lib/Tooling/Core/Lookup.cpp", 179, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(ReplacementString.startswith("::") && |
179 | (0) . __assert_fail ("ReplacementString.startswith(\"..\") && \"Expected fully-qualified name!\"", "/home/seafit/code_projects/clang_source/clang/lib/Tooling/Core/Lookup.cpp", 179, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "Expected fully-qualified name!"); |
180 | |
181 | |
182 | |
183 | |
184 | |
185 | |
186 | |
187 | |
188 | |
189 | const bool class_name_only = !Use; |
190 | const bool in_global_namespace = |
191 | isa<TranslationUnitDecl>(FromDecl->getDeclContext()); |
192 | const bool is_class_forward_decl = |
193 | isa<CXXRecordDecl>(FromDecl) && |
194 | !cast<CXXRecordDecl>(FromDecl)->isCompleteDefinition(); |
195 | if (class_name_only && !in_global_namespace && !is_class_forward_decl && |
196 | !usingFromDifferentCanonicalNamespace(FromDecl->getDeclContext(), |
197 | UseContext)) { |
198 | auto Pos = ReplacementString.rfind("::"); |
199 | return Pos != StringRef::npos ? ReplacementString.substr(Pos + 2) |
200 | : ReplacementString; |
201 | } |
202 | |
203 | |
204 | |
205 | |
206 | StringRef Suggested = getBestNamespaceSubstr(UseContext, ReplacementString, |
207 | isFullyQualified(Use)); |
208 | |
209 | return disambiguateSpellingInScope(Suggested, ReplacementString, *UseContext); |
210 | } |
211 | |