Coverage Report

Created: 2018-09-23 03:40

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/include/clang/Sema/TypoCorrection.h
Line
Count
Source (jump to first uncovered line)
1
//===- TypoCorrection.h - Class for typo correction results -----*- C++ -*-===//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
//
10
// This file defines the TypoCorrection class, which stores the results of
11
// Sema's typo correction (Sema::CorrectTypo).
12
//
13
//===----------------------------------------------------------------------===//
14
15
#ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H
16
#define LLVM_CLANG_SEMA_TYPOCORRECTION_H
17
18
#include "clang/AST/Decl.h"
19
#include "clang/AST/DeclarationName.h"
20
#include "clang/Basic/LLVM.h"
21
#include "clang/Basic/PartialDiagnostic.h"
22
#include "clang/Basic/SourceLocation.h"
23
#include "clang/Sema/DeclSpec.h"
24
#include "llvm/ADT/ArrayRef.h"
25
#include "llvm/ADT/SmallVector.h"
26
#include "llvm/Support/Casting.h"
27
#include <cstddef>
28
#include <limits>
29
#include <string>
30
#include <utility>
31
#include <vector>
32
33
namespace clang {
34
35
class DeclContext;
36
class IdentifierInfo;
37
class LangOptions;
38
class MemberExpr;
39
class NestedNameSpecifier;
40
class Sema;
41
42
/// Simple class containing the result of Sema::CorrectTypo
43
class TypoCorrection {
44
public:
45
  // "Distance" for unusable corrections
46
  static const unsigned InvalidDistance = std::numeric_limits<unsigned>::max();
47
48
  // The largest distance still considered valid (larger edit distances are
49
  // mapped to InvalidDistance by getEditDistance).
50
  static const unsigned MaximumDistance = 10000U;
51
52
  // Relative weightings of the "edit distance" components. The higher the
53
  // weight, the more of a penalty to fitness the component will give (higher
54
  // weights mean greater contribution to the total edit distance, with the
55
  // best correction candidates having the lowest edit distance).
56
  static const unsigned CharDistanceWeight = 100U;
57
  static const unsigned QualifierDistanceWeight = 110U;
58
  static const unsigned CallbackDistanceWeight = 150U;
59
60
  TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
61
                 NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0,
62
                 unsigned QualifierDistance = 0)
63
      : CorrectionName(Name), CorrectionNameSpec(NNS),
64
30.4k
        CharDistance(CharDistance), QualifierDistance(QualifierDistance) {
65
30.4k
    if (NameDecl)
66
0
      CorrectionDecls.push_back(NameDecl);
67
30.4k
  }
68
69
  TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = nullptr,
70
                 unsigned CharDistance = 0)
71
      : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
72
        CharDistance(CharDistance) {
73
    if (Name)
74
      CorrectionDecls.push_back(Name);
75
  }
76
77
  TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = nullptr,
78
                 unsigned CharDistance = 0)
79
      : CorrectionName(Name), CorrectionNameSpec(NNS),
80
        CharDistance(CharDistance) {}
81
82
24.3k
  TypoCorrection() = default;
83
84
  /// Gets the DeclarationName of the typo correction
85
401
  DeclarationName getCorrection() const { return CorrectionName; }
86
87
233k
  IdentifierInfo *getCorrectionAsIdentifierInfo() const {
88
233k
    return CorrectionName.getAsIdentifierInfo();
89
233k
  }
90
91
  /// Gets the NestedNameSpecifier needed to use the typo correction
92
1.43k
  NestedNameSpecifier *getCorrectionSpecifier() const {
93
1.43k
    return CorrectionNameSpec;
94
1.43k
  }
95
96
84.7k
  void setCorrectionSpecifier(NestedNameSpecifier *NNS) {
97
84.7k
    CorrectionNameSpec = NNS;
98
84.7k
    ForceSpecifierReplacement = (NNS != nullptr);
99
84.7k
  }
100
101
2.99k
  void WillReplaceSpecifier(bool ForceReplacement) {
102
2.99k
    ForceSpecifierReplacement = ForceReplacement;
103
2.99k
  }
104
105
5.97k
  bool WillReplaceSpecifier() const {
106
5.97k
    return ForceSpecifierReplacement;
107
5.97k
  }
108
109
84.7k
  void setQualifierDistance(unsigned ED) {
110
84.7k
    QualifierDistance = ED;
111
84.7k
  }
112
113
88.4k
  void setCallbackDistance(unsigned ED) {
114
88.4k
    CallbackDistance = ED;
115
88.4k
  }
116
117
  // Convert the given weighted edit distance to a roughly equivalent number of
118
  // single-character edits (typically for comparison to the length of the
119
  // string being edited).
120
92.5k
  static unsigned NormalizeEditDistance(unsigned ED) {
121
92.5k
    if (ED > MaximumDistance)
122
0
      return InvalidDistance;
123
92.5k
    return (ED + CharDistanceWeight / 2) / CharDistanceWeight;
124
92.5k
  }
125
126
  /// Gets the "edit distance" of the typo correction from the typo.
127
  /// If Normalized is true, scale the distance down by the CharDistanceWeight
128
  /// to return the edit distance in terms of single-character edits.
129
104k
  unsigned getEditDistance(bool Normalized = true) const {
130
104k
    if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance ||
131
104k
        CallbackDistance > MaximumDistance)
132
1.35k
      return InvalidDistance;
133
103k
    unsigned ED =
134
103k
        CharDistance * CharDistanceWeight +
135
103k
        QualifierDistance * QualifierDistanceWeight +
136
103k
        CallbackDistance * CallbackDistanceWeight;
137
103k
    if (ED > MaximumDistance)
138
0
      return InvalidDistance;
139
103k
    // Half the CharDistanceWeight is added to ED to simulate rounding since
140
103k
    // integer division truncates the value (i.e. round-to-nearest-int instead
141
103k
    // of round-to-zero).
142
103k
    return Normalized ? 
NormalizeEditDistance(ED)89.2k
:
ED14.3k
;
143
103k
  }
144
145
  /// Get the correction declaration found by name lookup (before we
146
  /// looked through using shadow declarations and the like).
147
18.1k
  NamedDecl *getFoundDecl() const {
148
18.1k
    return hasCorrectionDecl() ? 
*(CorrectionDecls.begin())8.08k
:
nullptr10.0k
;
149
18.1k
  }
150
151
  /// Gets the pointer to the declaration of the typo correction
152
16.4k
  NamedDecl *getCorrectionDecl() const {
153
16.4k
    auto *D = getFoundDecl();
154
16.4k
    return D ? 
D->getUnderlyingDecl()6.40k
:
nullptr10.0k
;
155
16.4k
  }
156
  template <class DeclClass>
157
811
  DeclClass *getCorrectionDeclAs() const {
158
811
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
811
  }
clang::FieldDecl* clang::TypoCorrection::getCorrectionDeclAs<clang::FieldDecl>() const
Line
Count
Source
157
233
  DeclClass *getCorrectionDeclAs() const {
158
233
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
233
  }
clang::VarDecl* clang::TypoCorrection::getCorrectionDeclAs<clang::VarDecl>() const
Line
Count
Source
157
19
  DeclClass *getCorrectionDeclAs() const {
158
19
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
19
  }
clang::NamespaceDecl* clang::TypoCorrection::getCorrectionDeclAs<clang::NamespaceDecl>() const
Line
Count
Source
157
15
  DeclClass *getCorrectionDeclAs() const {
158
15
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
15
  }
clang::ObjCInterfaceDecl* clang::TypoCorrection::getCorrectionDeclAs<clang::ObjCInterfaceDecl>() const
Line
Count
Source
157
109
  DeclClass *getCorrectionDeclAs() const {
158
109
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
109
  }
clang::FunctionDecl* clang::TypoCorrection::getCorrectionDeclAs<clang::FunctionDecl>() const
Line
Count
Source
157
76
  DeclClass *getCorrectionDeclAs() const {
158
76
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
76
  }
clang::TypeDecl* clang::TypoCorrection::getCorrectionDeclAs<clang::TypeDecl>() const
Line
Count
Source
157
7
  DeclClass *getCorrectionDeclAs() const {
158
7
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
7
  }
clang::ObjCProtocolDecl* clang::TypoCorrection::getCorrectionDeclAs<clang::ObjCProtocolDecl>() const
Line
Count
Source
157
10
  DeclClass *getCorrectionDeclAs() const {
158
10
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
10
  }
clang::ImplicitParamDecl* clang::TypoCorrection::getCorrectionDeclAs<clang::ImplicitParamDecl>() const
Line
Count
Source
157
301
  DeclClass *getCorrectionDeclAs() const {
158
301
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
301
  }
clang::ObjCIvarDecl* clang::TypoCorrection::getCorrectionDeclAs<clang::ObjCIvarDecl>() const
Line
Count
Source
157
22
  DeclClass *getCorrectionDeclAs() const {
158
22
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
22
  }
clang::ObjCPropertyDecl* clang::TypoCorrection::getCorrectionDeclAs<clang::ObjCPropertyDecl>() const
Line
Count
Source
157
19
  DeclClass *getCorrectionDeclAs() const {
158
19
    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159
19
  }
160
161
  /// Clears the list of NamedDecls.
162
84.7k
  void ClearCorrectionDecls() {
163
84.7k
    CorrectionDecls.clear();
164
84.7k
  }
165
166
  /// Clears the list of NamedDecls before adding the new one.
167
307
  void setCorrectionDecl(NamedDecl *CDecl) {
168
307
    CorrectionDecls.clear();
169
307
    addCorrectionDecl(CDecl);
170
307
  }
171
172
  /// Clears the list of NamedDecls and adds the given set.
173
374
  void setCorrectionDecls(ArrayRef<NamedDecl*> Decls) {
174
374
    CorrectionDecls.clear();
175
374
    CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end());
176
374
  }
177
178
  /// Add the given NamedDecl to the list of NamedDecls that are the
179
  /// declarations associated with the DeclarationName of this TypoCorrection
180
  void addCorrectionDecl(NamedDecl *CDecl);
181
182
  std::string getAsString(const LangOptions &LO) const;
183
184
950
  std::string getQuoted(const LangOptions &LO) const {
185
950
    return "'" + getAsString(LO) + "'";
186
950
  }
187
188
  /// Returns whether this TypoCorrection has a non-empty DeclarationName
189
18.6k
  explicit operator bool() const { return bool(CorrectionName); }
190
191
  /// Mark this TypoCorrection as being a keyword.
192
  /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
193
  /// added to the list of the correction's NamedDecl pointers, NULL is added
194
  /// as the only element in the list to mark this TypoCorrection as a keyword.
195
106
  void makeKeyword() {
196
106
    CorrectionDecls.clear();
197
106
    CorrectionDecls.push_back(nullptr);
198
106
    ForceSpecifierReplacement = true;
199
106
  }
200
201
  // Check if this TypoCorrection is a keyword by checking if the first
202
  // item in CorrectionDecls is NULL.
203
33.3k
  bool isKeyword() const {
204
33.3k
    return !CorrectionDecls.empty() && 
CorrectionDecls.front() == nullptr18.3k
;
205
33.3k
  }
206
207
  // Check if this TypoCorrection is the given keyword.
208
  template<std::size_t StrLen>
209
8
  bool isKeyword(const char (&Str)[StrLen]) const {
210
8
    return isKeyword() && 
getCorrectionAsIdentifierInfo()->isStr(Str)5
;
211
8
  }
212
213
  // Returns true if the correction either is a keyword or has a known decl.
214
26.7k
  bool isResolved() const { return !CorrectionDecls.empty(); }
215
216
74
  bool isOverloaded() const {
217
74
    return CorrectionDecls.size() > 1;
218
74
  }
219
220
  void setCorrectionRange(CXXScopeSpec *SS,
221
34.7k
                          const DeclarationNameInfo &TypoName) {
222
34.7k
    CorrectionRange = TypoName.getSourceRange();
223
34.7k
    if (ForceSpecifierReplacement && 
SS2.76k
&&
!SS->isEmpty()2.25k
)
224
522
      CorrectionRange.setBegin(SS->getBeginLoc());
225
34.7k
  }
226
227
4.87k
  SourceRange getCorrectionRange() const {
228
4.87k
    return CorrectionRange;
229
4.87k
  }
230
231
  using decl_iterator = SmallVectorImpl<NamedDecl *>::iterator;
232
233
4.89k
  decl_iterator begin() {
234
4.89k
    return isKeyword() ? 
CorrectionDecls.end()143
:
CorrectionDecls.begin()4.75k
;
235
4.89k
  }
236
237
4.51k
  decl_iterator end() { return CorrectionDecls.end(); }
238
239
  using const_decl_iterator = SmallVectorImpl<NamedDecl *>::const_iterator;
240
241
1.93k
  const_decl_iterator begin() const {
242
1.93k
    return isKeyword() ? 
CorrectionDecls.end()0
: CorrectionDecls.begin();
243
1.93k
  }
244
245
1.93k
  const_decl_iterator end() const { return CorrectionDecls.end(); }
246
247
  /// Returns whether this typo correction is correcting to a
248
  /// declaration that was declared in a module that has not been imported.
249
9.69k
  bool requiresImport() const { return RequiresImport; }
250
4.33k
  void setRequiresImport(bool Req) { RequiresImport = Req; }
251
252
  /// Extra diagnostics are printed after the first diagnostic for the typo.
253
  /// This can be used to attach external notes to the diag.
254
  void addExtraDiagnostic(PartialDiagnostic PD) {
255
    ExtraDiagnostics.push_back(std::move(PD));
256
  }
257
739
  ArrayRef<PartialDiagnostic> getExtraDiagnostics() const {
258
739
    return ExtraDiagnostics;
259
739
  }
260
261
private:
262
18.1k
  bool hasCorrectionDecl() const {
263
18.1k
    return (!isKeyword() && 
!CorrectionDecls.empty()17.9k
);
264
18.1k
  }
265
266
  // Results.
267
  DeclarationName CorrectionName;
268
  NestedNameSpecifier *CorrectionNameSpec = nullptr;
269
  SmallVector<NamedDecl *, 1> CorrectionDecls;
270
  unsigned CharDistance = 0;
271
  unsigned QualifierDistance = 0;
272
  unsigned CallbackDistance = 0;
273
  SourceRange CorrectionRange;
274
  bool ForceSpecifierReplacement = false;
275
  bool RequiresImport = false;
276
277
  std::vector<PartialDiagnostic> ExtraDiagnostics;
278
};
279
280
/// Base class for callback objects used by Sema::CorrectTypo to check
281
/// the validity of a potential typo correction.
282
class CorrectionCandidateCallback {
283
public:
284
  static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
285
286
  explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr,
287
                                       NestedNameSpecifier *TypoNNS = nullptr)
288
21.5M
      : Typo(Typo), TypoNNS(TypoNNS) {}
289
290
21.5M
  virtual ~CorrectionCandidateCallback() = default;
291
292
  /// Simple predicate used by the default RankCandidate to
293
  /// determine whether to return an edit distance of 0 or InvalidDistance.
294
  /// This can be overridden by validators that only need to determine if a
295
  /// candidate is viable, without ranking potentially viable candidates.
296
  /// Only ValidateCandidate or RankCandidate need to be overridden by a
297
  /// callback wishing to check the viability of correction candidates.
298
  /// The default predicate always returns true if the candidate is not a type
299
  /// name or keyword, true for types if WantTypeSpecifiers is true, and true
300
  /// for keywords if WantTypeSpecifiers, WantExpressionKeywords,
301
  /// WantCXXNamedCasts, WantRemainingKeywords, or WantObjCSuper is true.
302
  virtual bool ValidateCandidate(const TypoCorrection &candidate);
303
304
  /// Method used by Sema::CorrectTypo to assign an "edit distance" rank
305
  /// to a candidate (where a lower value represents a better candidate), or
306
  /// returning InvalidDistance if the candidate is not at all viable. For
307
  /// validation callbacks that only need to determine if a candidate is viable,
308
  /// the default RankCandidate returns either 0 or InvalidDistance depending
309
  /// whether ValidateCandidate returns true or false.
310
3.67k
  virtual unsigned RankCandidate(const TypoCorrection &candidate) {
311
3.67k
    return (!MatchesTypo(candidate) && 
ValidateCandidate(candidate)3.67k
)
312
3.67k
               ? 
02.32k
313
3.67k
               : 
InvalidDistance1.35k
;
314
3.67k
  }
315
316
5.10k
  void setTypoName(IdentifierInfo *II) { Typo = II; }
317
0
  void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; }
318
319
  // Flags for context-dependent keywords. WantFunctionLikeCasts is only
320
  // used/meaningful when WantCXXNamedCasts is false.
321
  // TODO: Expand these to apply to non-keywords or possibly remove them.
322
  bool WantTypeSpecifiers = true;
323
  bool WantExpressionKeywords = true;
324
  bool WantCXXNamedCasts = true;
325
  bool WantFunctionLikeCasts = true;
326
  bool WantRemainingKeywords = true;
327
  bool WantObjCSuper = false;
328
  // Temporary hack for the one case where a CorrectTypoContext enum is used
329
  // when looking up results.
330
  bool IsObjCIvarLookup = false;
331
  bool IsAddressOfOperand = false;
332
333
protected:
334
3.67k
  bool MatchesTypo(const TypoCorrection &candidate) {
335
3.67k
    return Typo && 
candidate.isResolved()559
&&
!candidate.requiresImport()555
&&
336
3.67k
           
candidate.getCorrectionAsIdentifierInfo() == Typo499
&&
337
3.67k
           // FIXME: This probably does not return true when both
338
3.67k
           // NestedNameSpecifiers have the same textual representation.
339
3.67k
           
candidate.getCorrectionSpecifier() == TypoNNS225
;
340
3.67k
  }
341
342
  IdentifierInfo *Typo;
343
  NestedNameSpecifier *TypoNNS;
344
};
345
346
/// Simple template class for restricting typo correction candidates
347
/// to ones having a single Decl* of the given type.
348
template <class C>
349
class DeclFilterCCC : public CorrectionCandidateCallback {
350
public:
351
111
  bool ValidateCandidate(const TypoCorrection &candidate) override {
352
111
    return candidate.getCorrectionDeclAs<C>();
353
111
  }
clang::DeclFilterCCC<clang::ObjCInterfaceDecl>::ValidateCandidate(clang::TypoCorrection const&)
Line
Count
Source
351
1
  bool ValidateCandidate(const TypoCorrection &candidate) override {
352
1
    return candidate.getCorrectionDeclAs<C>();
353
1
  }
clang::DeclFilterCCC<clang::FunctionDecl>::ValidateCandidate(clang::TypoCorrection const&)
Line
Count
Source
351
76
  bool ValidateCandidate(const TypoCorrection &candidate) override {
352
76
    return candidate.getCorrectionDeclAs<C>();
353
76
  }
clang::DeclFilterCCC<clang::ObjCProtocolDecl>::ValidateCandidate(clang::TypoCorrection const&)
Line
Count
Source
351
1
  bool ValidateCandidate(const TypoCorrection &candidate) override {
352
1
    return candidate.getCorrectionDeclAs<C>();
353
1
  }
clang::DeclFilterCCC<clang::ObjCIvarDecl>::ValidateCandidate(clang::TypoCorrection const&)
Line
Count
Source
351
13
  bool ValidateCandidate(const TypoCorrection &candidate) override {
352
13
    return candidate.getCorrectionDeclAs<C>();
353
13
  }
clang::DeclFilterCCC<clang::ObjCPropertyDecl>::ValidateCandidate(clang::TypoCorrection const&)
Line
Count
Source
351
19
  bool ValidateCandidate(const TypoCorrection &candidate) override {
352
19
    return candidate.getCorrectionDeclAs<C>();
353
19
  }
clang::DeclFilterCCC<clang::VarDecl>::ValidateCandidate(clang::TypoCorrection const&)
Line
Count
Source
351
1
  bool ValidateCandidate(const TypoCorrection &candidate) override {
352
1
    return candidate.getCorrectionDeclAs<C>();
353
1
  }
354
};
355
356
// Callback class to limit the allowed keywords and to only accept typo
357
// corrections that are keywords or whose decls refer to functions (or template
358
// functions) that accept the given number of arguments.
359
class FunctionCallFilterCCC : public CorrectionCandidateCallback {
360
public:
361
  FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
362
                        bool HasExplicitTemplateArgs,
363
                        MemberExpr *ME = nullptr);
364
365
  bool ValidateCandidate(const TypoCorrection &candidate) override;
366
367
private:
368
  unsigned NumArgs;
369
  bool HasExplicitTemplateArgs;
370
  DeclContext *CurContext;
371
  MemberExpr *MemberFn;
372
};
373
374
// Callback class that effectively disabled typo correction
375
class NoTypoCorrectionCCC : public CorrectionCandidateCallback {
376
public:
377
0
  NoTypoCorrectionCCC() {
378
0
    WantTypeSpecifiers = false;
379
0
    WantExpressionKeywords = false;
380
0
    WantCXXNamedCasts = false;
381
0
    WantFunctionLikeCasts = false;
382
0
    WantRemainingKeywords = false;
383
0
  }
384
385
0
  bool ValidateCandidate(const TypoCorrection &candidate) override {
386
0
    return false;
387
0
  }
388
};
389
390
} // namespace clang
391
392
#endif // LLVM_CLANG_SEMA_TYPOCORRECTION_H