Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/AST/ComparisonCategories.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- ComparisonCategories.cpp - Three Way Comparison Data -----*- C++ -*-===//
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 the Comparison Category enum and data types, which
10
//  store the types and expressions needed to support operator<=>
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/AST/ComparisonCategories.h"
15
#include "clang/AST/Decl.h"
16
#include "clang/AST/DeclCXX.h"
17
#include "clang/AST/Type.h"
18
#include "llvm/ADT/SmallVector.h"
19
20
using namespace clang;
21
22
46
bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
23
46
  assert(VD && "must have var decl");
24
46
  if (!VD->checkInitIsICE())
25
0
    return false;
26
46
27
46
  // Before we attempt to get the value of the first field, ensure that we
28
46
  // actually have one (and only one) field.
29
46
  auto *Record = VD->getType()->getAsCXXRecordDecl();
30
46
  if (std::distance(Record->field_begin(), Record->field_end()) != 1 ||
31
46
      !Record->field_begin()->getType()->isIntegralOrEnumerationType())
32
0
    return false;
33
46
34
46
  return true;
35
46
}
36
37
/// Attempt to determine the integer value used to represent the comparison
38
/// category result by evaluating the initializer for the specified VarDecl as
39
/// a constant expression and retreiving the value of the class's first
40
/// (and only) field.
41
///
42
/// Note: The STL types are expected to have the form:
43
///    struct X { T value; };
44
/// where T is an integral or enumeration type.
45
45
llvm::APSInt ComparisonCategoryInfo::ValueInfo::getIntValue() const {
46
45
  assert(hasValidIntValue() && "must have a valid value");
47
45
  return VD->evaluateValue()->getStructField(0).getInt();
48
45
}
49
50
ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
51
167
    ComparisonCategoryResult ValueKind) const {
52
167
  // Check if we already have a cache entry for this value.
53
167
  auto It = llvm::find_if(
54
391
      Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; });
55
167
  if (It != Objects.end())
56
115
    return &(*It);
57
52
58
52
  // We don't have a cached result. Lookup the variable declaration and create
59
52
  // a new entry representing it.
60
52
  DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
61
52
      &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
62
52
  if (Lookup.size() != 1 || 
!isa<VarDecl>(Lookup.front())51
)
63
1
    return nullptr;
64
51
  Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
65
51
  return &Objects.back();
66
51
}
67
68
static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
69
18
                                               NamespaceDecl *&StdNS) {
70
18
  if (!StdNS) {
71
7
    DeclContextLookupResult Lookup =
72
7
        Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
73
7
    if (Lookup.size() == 1)
74
5
      StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
75
7
  }
76
18
  return StdNS;
77
18
}
78
79
static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
80
                                          const NamespaceDecl *StdNS,
81
16
                                          ComparisonCategoryType Kind) {
82
16
  StringRef Name = ComparisonCategories::getCategoryString(Kind);
83
16
  DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
84
16
  if (Lookup.size() == 1)
85
16
    if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
86
16
      return RD;
87
0
  return nullptr;
88
0
}
89
90
const ComparisonCategoryInfo *
91
189
ComparisonCategories::lookupInfo(ComparisonCategoryType Kind) const {
92
189
  auto It = Data.find(static_cast<char>(Kind));
93
189
  if (It != Data.end())
94
171
    return &It->second;
95
18
96
18
  if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
97
16
    if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
98
16
      return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
99
2
100
2
  return nullptr;
101
2
}
102
103
const ComparisonCategoryInfo *
104
326
ComparisonCategories::lookupInfoForType(QualType Ty) const {
105
326
  assert(!Ty.isNull() && "type must be non-null");
106
326
  using CCT = ComparisonCategoryType;
107
326
  auto *RD = Ty->getAsCXXRecordDecl();
108
326
  if (!RD)
109
0
    return nullptr;
110
326
111
326
  // Check to see if we have information for the specified type cached.
112
326
  const auto *CanonRD = RD->getCanonicalDecl();
113
582
  for (auto &KV : Data) {
114
582
    const ComparisonCategoryInfo &Info = KV.second;
115
582
    if (CanonRD == Info.Record->getCanonicalDecl())
116
324
      return &Info;
117
582
  }
118
326
119
326
  
if (2
!RD->getEnclosingNamespaceContext()->isStdNamespace()2
)
120
0
    return nullptr;
121
2
122
2
  // If not, check to see if the decl names a type in namespace std with a name
123
2
  // matching one of the comparison category types.
124
2
  for (unsigned I = static_cast<unsigned>(CCT::First),
125
2
                End = static_cast<unsigned>(CCT::Last);
126
10
       I <= End; 
++I8
) {
127
10
    CCT Kind = static_cast<CCT>(I);
128
10
129
10
    // We've found the comparison category type. Build a new cache entry for
130
10
    // it.
131
10
    if (getCategoryString(Kind) == RD->getName())
132
2
      return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
133
10
  }
134
2
135
2
  // We've found nothing. This isn't a comparison category type.
136
2
  
return nullptr0
;
137
2
}
138
139
326
const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) const {
140
326
  const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
141
326
  assert(Info && "info for comparison category not found");
142
326
  return *Info;
143
326
}
144
145
200
QualType ComparisonCategoryInfo::getType() const {
146
200
  assert(Record);
147
200
  return QualType(Record->getTypeForDecl(), 0);
148
200
}
149
150
28
StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) {
151
28
  using CCKT = ComparisonCategoryType;
152
28
  switch (Kind) {
153
28
  case CCKT::WeakEquality:
154
5
    return "weak_equality";
155
28
  case CCKT::StrongEquality:
156
6
    return "strong_equality";
157
28
  case CCKT::PartialOrdering:
158
7
    return "partial_ordering";
159
28
  case CCKT::WeakOrdering:
160
2
    return "weak_ordering";
161
28
  case CCKT::StrongOrdering:
162
8
    return "strong_ordering";
163
0
  }
164
0
  llvm_unreachable("unhandled cases in switch");
165
0
}
166
167
100
StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) {
168
100
  using CCVT = ComparisonCategoryResult;
169
100
  switch (Kind) {
170
100
  case CCVT::Equal:
171
15
    return "equal";
172
100
  case CCVT::Nonequal:
173
6
    return "nonequal";
174
100
  case CCVT::Equivalent:
175
30
    return "equivalent";
176
100
  case CCVT::Nonequivalent:
177
12
    return "nonequivalent";
178
100
  case CCVT::Less:
179
16
    return "less";
180
100
  case CCVT::Greater:
181
15
    return "greater";
182
100
  case CCVT::Unordered:
183
6
    return "unordered";
184
0
  }
185
0
  llvm_unreachable("unhandled case in switch");
186
0
}
187
188
std::vector<ComparisonCategoryResult>
189
15
ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) {
190
15
  using CCT = ComparisonCategoryType;
191
15
  using CCR = ComparisonCategoryResult;
192
15
  std::vector<CCR> Values;
193
15
  Values.reserve(6);
194
15
  Values.push_back(CCR::Equivalent);
195
15
  bool IsStrong = (Type == CCT::StrongEquality || 
Type == CCT::StrongOrdering12
);
196
15
  if (IsStrong)
197
8
    Values.push_back(CCR::Equal);
198
15
  if (Type == CCT::StrongOrdering || 
Type == CCT::WeakOrdering10
||
199
15
      
Type == CCT::PartialOrdering10
) {
200
9
    Values.push_back(CCR::Less);
201
9
    Values.push_back(CCR::Greater);
202
9
  } else {
203
6
    Values.push_back(CCR::Nonequivalent);
204
6
    if (IsStrong)
205
3
      Values.push_back(CCR::Nonequal);
206
6
  }
207
15
  if (Type == CCT::PartialOrdering)
208
4
    Values.push_back(CCR::Unordered);
209
15
  return Values;
210
15
}