1//===- ASTStructuralEquivalence.h -------------------------------*- 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 StructuralEquivalenceContext class which checks for
10//  structural equivalence between types.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
15#define LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
16
17#include "clang/AST/DeclBase.h"
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/DenseSet.h"
20#include "llvm/ADT/Optional.h"
21#include <queue>
22#include <utility>
23
24namespace clang {
25
26class ASTContext;
27class Decl;
28class DiagnosticBuilder;
29class QualType;
30class RecordDecl;
31class SourceLocation;
32
33/// \brief Whether to perform a normal or minimal equivalence check.
34/// In case of `Minimal`, we do not perform a recursive check of decls with
35/// external storage.
36enum class StructuralEquivalenceKind {
37  Default,
38  Minimal,
39};
40
41struct StructuralEquivalenceContext {
42  /// AST contexts for which we are checking structural equivalence.
43  ASTContext &FromCtx, &ToCtx;
44
45  // Queue of from-to Decl pairs that are to be checked to determine the final
46  // result of equivalence of a starting Decl pair.
47  std::queue<std::pair<Decl *, Decl *>> DeclsToCheck;
48
49  // Set of from-to Decl pairs that are already visited during the check
50  // (are in or were once in \c DeclsToCheck) of a starting Decl pair.
51  llvm::DenseSet<std::pair<Decl *, Decl *>> VisitedDecls;
52
53  /// Declaration (from, to) pairs that are known not to be equivalent
54  /// (which we have already complained about).
55  llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls;
56
57  StructuralEquivalenceKind EqKind;
58
59  /// Whether we're being strict about the spelling of types when
60  /// unifying two types.
61  bool StrictTypeSpelling;
62
63  /// Whether warn or error on tag type mismatches.
64  bool ErrorOnTagTypeMismatch;
65
66  /// Whether to complain about failures.
67  bool Complain;
68
69  /// \c true if the last diagnostic came from ToCtx.
70  bool LastDiagFromC2 = false;
71
72  StructuralEquivalenceContext(
73      ASTContext &FromCtx, ASTContext &ToCtx,
74      llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls,
75      StructuralEquivalenceKind EqKind,
76      bool StrictTypeSpelling = false, bool Complain = true,
77      bool ErrorOnTagTypeMismatch = false)
78      : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls),
79        EqKind(EqKind), StrictTypeSpelling(StrictTypeSpelling),
80        ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain) {}
81
82  DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID);
83  DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID);
84
85  /// Determine whether the two declarations are structurally
86  /// equivalent.
87  /// Implementation functions (all static functions in
88  /// ASTStructuralEquivalence.cpp) must never call this function because that
89  /// will wreak havoc the internal state (\c DeclsToCheck and
90  /// \c VisitedDecls members) and can cause faulty equivalent results.
91  bool IsEquivalent(Decl *D1, Decl *D2);
92
93  /// Determine whether the two types are structurally equivalent.
94  /// Implementation functions (all static functions in
95  /// ASTStructuralEquivalence.cpp) must never call this function because that
96  /// will wreak havoc the internal state (\c DeclsToCheck and
97  /// \c VisitedDecls members) and can cause faulty equivalent results.
98  bool IsEquivalent(QualType T1, QualType T2);
99
100  /// Find the index of the given anonymous struct/union within its
101  /// context.
102  ///
103  /// \returns Returns the index of this anonymous struct/union in its context,
104  /// including the next assigned index (if none of them match). Returns an
105  /// empty option if the context is not a record, i.e.. if the anonymous
106  /// struct/union is at namespace or block scope.
107  ///
108  /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It
109  /// probably makes more sense in some other common place then here.
110  static llvm::Optional<unsigned>
111  findUntaggedStructOrUnionIndex(RecordDecl *Anon);
112
113  // If ErrorOnTagTypeMismatch is set, return the the error, otherwise get the
114  // relevant warning for the input error diagnostic.
115  unsigned getApplicableDiagnostic(unsigned ErrorDiagnostic);
116
117private:
118  /// Finish checking all of the structural equivalences.
119  ///
120  /// \returns true if the equivalence check failed (non-equivalence detected),
121  /// false if equivalence was detected.
122  bool Finish();
123
124  /// Check for common properties at Finish.
125  /// \returns true if D1 and D2 may be equivalent,
126  /// false if they are for sure not.
127  bool CheckCommonEquivalence(Decl *D1, Decl *D2);
128
129  /// Check for class dependent properties at Finish.
130  /// \returns true if D1 and D2 may be equivalent,
131  /// false if they are for sure not.
132  bool CheckKindSpecificEquivalence(Decl *D1, Decl *D2);
133};
134
135} // namespace clang
136
137#endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
138