Coverage Report

Created: 2020-09-19 12:23

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/Core/Lookup.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- Lookup.cpp - Framework for clang refactoring tools ---------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//  This file defines helper methods for clang tools performing name lookup.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/Tooling/Core/Lookup.h"
14
#include "clang/AST/ASTContext.h"
15
#include "clang/AST/Decl.h"
16
#include "clang/AST/DeclCXX.h"
17
#include "clang/AST/DeclarationName.h"
18
#include "clang/Basic/SourceLocation.h"
19
#include "clang/Basic/SourceManager.h"
20
#include "llvm/ADT/SmallVector.h"
21
using namespace clang;
22
using namespace clang::tooling;
23
24
// Gets all namespaces that \p Context is in as a vector (ignoring anonymous
25
// namespaces). The inner namespaces come before outer namespaces in the vector.
26
// For example, if the context is in the following namespace:
27
//    `namespace a { namespace b { namespace c ( ... ) } }`,
28
// the vector will be `{c, b, a}`.
29
static llvm::SmallVector<const NamespaceDecl *, 4>
30
372
getAllNamedNamespaces(const DeclContext *Context) {
31
372
  llvm::SmallVector<const NamespaceDecl *, 4> Namespaces;
32
716
  auto GetNextNamedNamespace = [](const DeclContext *Context) {
33
    // Look past non-namespaces and anonymous namespaces on FromContext.
34
1.28k
    while (Context && 
(915
!isa<NamespaceDecl>(Context)915
||
35
346
                       cast<NamespaceDecl>(Context)->isAnonymousNamespace()))
36
571
      Context = Context->getParent();
37
716
    return Context;
38
716
  };
39
716
  for (Context = GetNextNamedNamespace(Context); Context != nullptr;
40
344
       Context = GetNextNamedNamespace(Context->getParent()))
41
344
    Namespaces.push_back(cast<NamespaceDecl>(Context));
42
372
  return Namespaces;
43
372
}
44
45
// Returns true if the context in which the type is used and the context in
46
// which the type is declared are the same semantical namespace but different
47
// lexical namespaces.
48
static bool
49
usingFromDifferentCanonicalNamespace(const DeclContext *FromContext,
50
100
                                     const DeclContext *UseContext) {
51
  // We can skip anonymous namespace because:
52
  // 1. `FromContext` and `UseContext` must be in the same anonymous namespaces
53
  // since referencing across anonymous namespaces is not possible.
54
  // 2. If `FromContext` and `UseContext` are in the same anonymous namespace,
55
  // the function will still return `false` as expected.
56
100
  llvm::SmallVector<const NamespaceDecl *, 4> FromNamespaces =
57
100
      getAllNamedNamespaces(FromContext);
58
100
  llvm::SmallVector<const NamespaceDecl *, 4> UseNamespaces =
59
100
      getAllNamedNamespaces(UseContext);
60
  // If `UseContext` has fewer level of nested namespaces, it cannot be in the
61
  // same canonical namespace as the `FromContext`.
62
100
  if (UseNamespaces.size() < FromNamespaces.size())
63
4
    return false;
64
96
  unsigned Diff = UseNamespaces.size() - FromNamespaces.size();
65
96
  auto FromIter = FromNamespaces.begin();
66
  // Only compare `FromNamespaces` with namespaces in `UseNamespaces` that can
67
  // collide, i.e. the top N namespaces where N is the number of namespaces in
68
  // `FromNamespaces`.
69
96
  auto UseIter = UseNamespaces.begin() + Diff;
70
98
  for (; FromIter != FromNamespaces.end() && 
UseIter != UseNamespaces.end()96
;
71
96
       
++FromIter, ++UseIter2
) {
72
    // Literally the same namespace, not a collision.
73
96
    if (*FromIter == *UseIter)
74
62
      return false;
75
    // Now check the names. If they match we have a different canonical
76
    // namespace with the same name.
77
34
    if (cast<NamespaceDecl>(*FromIter)->getDeclName() ==
78
34
        cast<NamespaceDecl>(*UseIter)->getDeclName())
79
32
      return true;
80
34
  }
81
2
  assert(FromIter == FromNamespaces.end() && UseIter == UseNamespaces.end());
82
2
  return false;
83
96
}
84
85
static StringRef getBestNamespaceSubstr(const DeclContext *DeclA,
86
                                        StringRef NewName,
87
177
                                        bool HadLeadingColonColon) {
88
230
  while (true) {
89
497
    while (DeclA && 
!isa<NamespaceDecl>(DeclA)358
)
90
267
      DeclA = DeclA->getParent();
91
230
92
    // Fully qualified it is! Leave :: in place if it's there already.
93
230
    if (!DeclA)
94
139
      return HadLeadingColonColon ? 
NewName5
:
NewName.substr(2)134
;
95
91
96
    // Otherwise strip off redundant namespace qualifications from the new name.
97
    // We use the fully qualified name of the namespace and remove that part
98
    // from NewName if it has an identical prefix.
99
91
    std::string NS =
100
91
        "::" + cast<NamespaceDecl>(DeclA)->getQualifiedNameAsString() + "::";
101
91
    if (NewName.startswith(NS))
102
38
      return NewName.substr(NS.size());
103
53
104
    // No match yet. Strip of a namespace from the end of the chain and try
105
    // again. This allows to get optimal qualifications even if the old and new
106
    // decl only share common namespaces at a higher level.
107
53
    DeclA = DeclA->getParent();
108
53
  }
109
177
}
110
111
/// Check if the name specifier begins with a written "::".
112
177
static bool isFullyQualified(const NestedNameSpecifier *NNS) {
113
315
  while (NNS) {
114
146
    if (NNS->getKind() == NestedNameSpecifier::Global)
115
8
      return true;
116
138
    NNS = NNS->getPrefix();
117
138
  }
118
169
  return false;
119
177
}
120
121
// Adds more scope specifier to the spelled name until the spelling is not
122
// ambiguous. A spelling is ambiguous if the resolution of the symbol is
123
// ambiguous. For example, if QName is "::y::bar", the spelling is "y::bar", and
124
// context contains a nested namespace "a::y", then "y::bar" can be resolved to
125
// ::a::y::bar in the context, which can cause compile error.
126
// FIXME: consider using namespaces.
127
static std::string disambiguateSpellingInScope(StringRef Spelling,
128
                                               StringRef QName,
129
                                               const DeclContext &UseContext,
130
177
                                               SourceLocation UseLoc) {
131
177
  assert(QName.startswith("::"));
132
177
  assert(QName.endswith(Spelling));
133
177
  if (Spelling.startswith("::"))
134
5
    return std::string(Spelling);
135
172
136
172
  auto UnspelledSpecifier = QName.drop_back(Spelling.size());
137
172
  llvm::SmallVector<llvm::StringRef, 2> UnspelledScopes;
138
172
  UnspelledSpecifier.split(UnspelledScopes, "::", /*MaxSplit=*/-1,
139
172
                           /*KeepEmpty=*/false);
140
172
141
172
  llvm::SmallVector<const NamespaceDecl *, 4> EnclosingNamespaces =
142
172
      getAllNamedNamespaces(&UseContext);
143
172
  auto &AST = UseContext.getParentASTContext();
144
172
  StringRef TrimmedQName = QName.substr(2);
145
172
  const auto &SM = UseContext.getParentASTContext().getSourceManager();
146
172
  UseLoc = SM.getSpellingLoc(UseLoc);
147
172
148
175
  auto IsAmbiguousSpelling = [&](const llvm::StringRef CurSpelling) {
149
175
    if (CurSpelling.startswith("::"))
150
2
      return false;
151
    // Lookup the first component of Spelling in all enclosing namespaces
152
    // and check if there is any existing symbols with the same name but in
153
    // different scope.
154
173
    StringRef Head = CurSpelling.split("::").first;
155
97
    for (const auto *NS : EnclosingNamespaces) {
156
97
      auto LookupRes = NS->lookup(DeclarationName(&AST.Idents.get(Head)));
157
97
      if (!LookupRes.empty()) {
158
4
        for (const NamedDecl *Res : LookupRes)
159
          // If `Res` is not visible in `UseLoc`, we don't consider it
160
          // ambiguous. For example, a reference in a header file should not be
161
          // affected by a potentially ambiguous name in some file that includes
162
          // the header.
163
4
          if (!TrimmedQName.startswith(Res->getQualifiedNameAsString()) &&
164
4
              SM.isBeforeInTranslationUnit(
165
4
                  SM.getSpellingLoc(Res->getLocation()), UseLoc))
166
3
            return true;
167
4
      }
168
97
    }
169
170
    return false;
170
173
  };
171
172
172
  // Add more qualifiers until the spelling is not ambiguous.
173
172
  std::string Disambiguated = std::string(Spelling);
174
175
  while (IsAmbiguousSpelling(Disambiguated)) {
175
3
    if (UnspelledScopes.empty()) {
176
2
      Disambiguated = "::" + Disambiguated;
177
1
    } else {
178
1
      Disambiguated = (UnspelledScopes.back() + "::" + Disambiguated).str();
179
1
      UnspelledScopes.pop_back();
180
1
    }
181
3
  }
182
172
  return Disambiguated;
183
172
}
184
185
std::string tooling::replaceNestedName(const NestedNameSpecifier *Use,
186
                                       SourceLocation UseLoc,
187
                                       const DeclContext *UseContext,
188
                                       const NamedDecl *FromDecl,
189
245
                                       StringRef ReplacementString) {
190
245
  assert(ReplacementString.startswith("::") &&
191
245
         "Expected fully-qualified name!");
192
245
193
  // We can do a raw name replacement when we are not inside the namespace for
194
  // the original class/function and it is not in the global namespace.  The
195
  // assumption is that outside the original namespace we must have a using
196
  // statement that makes this work out and that other parts of this refactor
197
  // will automatically fix using statements to point to the new class/function.
198
  // However, if the `FromDecl` is a class forward declaration, the reference is
199
  // still considered as referring to the original definition, so we can't do a
200
  // raw name replacement in this case.
201
245
  const bool class_name_only = !Use;
202
245
  const bool in_global_namespace =
203
245
      isa<TranslationUnitDecl>(FromDecl->getDeclContext());
204
245
  const bool is_class_forward_decl =
205
245
      isa<CXXRecordDecl>(FromDecl) &&
206
140
      !cast<CXXRecordDecl>(FromDecl)->isCompleteDefinition();
207
245
  if (class_name_only && 
!in_global_namespace121
&&
!is_class_forward_decl102
&&
208
100
      !usingFromDifferentCanonicalNamespace(FromDecl->getDeclContext(),
209
68
                                            UseContext)) {
210
68
    auto Pos = ReplacementString.rfind("::");
211
68
    return std::string(Pos != StringRef::npos
212
68
                           ? ReplacementString.substr(Pos + 2)
213
0
                           : ReplacementString);
214
68
  }
215
  // We did not match this because of a using statement, so we will need to
216
  // figure out how good a namespace match we have with our destination type.
217
  // We work backwards (from most specific possible namespace to least
218
  // specific).
219
177
  StringRef Suggested = getBestNamespaceSubstr(UseContext, ReplacementString,
220
177
                                               isFullyQualified(Use));
221
177
222
177
  return disambiguateSpellingInScope(Suggested, ReplacementString, *UseContext,
223
177
                                     UseLoc);
224
177
}