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 <optional>
21 #include <queue>
22 #include <utility>
23 
24 namespace clang {
25 
26 class ASTContext;
27 class Decl;
28 class DiagnosticBuilder;
29 class QualType;
30 class RecordDecl;
31 class 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.
36 enum class StructuralEquivalenceKind {
37   Default,
38   Minimal,
39 };
40 
41 struct 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   /// Whether to ignore comparing the depth of template param(TemplateTypeParm)
73   bool IgnoreTemplateParmDepth;
74 
75   StructuralEquivalenceContext(
76       ASTContext &FromCtx, ASTContext &ToCtx,
77       llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls,
78       StructuralEquivalenceKind EqKind, bool StrictTypeSpelling = false,
79       bool Complain = true, bool ErrorOnTagTypeMismatch = false,
80       bool IgnoreTemplateParmDepth = false)
81       : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls),
82         EqKind(EqKind), StrictTypeSpelling(StrictTypeSpelling),
83         ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain),
84         IgnoreTemplateParmDepth(IgnoreTemplateParmDepth) {}
85 
86   DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID);
87   DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID);
88 
89   /// Determine whether the two declarations are structurally
90   /// equivalent.
91   /// Implementation functions (all static functions in
92   /// ASTStructuralEquivalence.cpp) must never call this function because that
93   /// will wreak havoc the internal state (\c DeclsToCheck and
94   /// \c VisitedDecls members) and can cause faulty equivalent results.
95   bool IsEquivalent(Decl *D1, Decl *D2);
96 
97   /// Determine whether the two types are structurally equivalent.
98   /// Implementation functions (all static functions in
99   /// ASTStructuralEquivalence.cpp) must never call this function because that
100   /// will wreak havoc the internal state (\c DeclsToCheck and
101   /// \c VisitedDecls members) and can cause faulty equivalent results.
102   bool IsEquivalent(QualType T1, QualType T2);
103 
104   /// Determine whether the two statements are structurally equivalent.
105   /// Implementation functions (all static functions in
106   /// ASTStructuralEquivalence.cpp) must never call this function because that
107   /// will wreak havoc the internal state (\c DeclsToCheck and
108   /// \c VisitedDecls members) and can cause faulty equivalent results.
109   bool IsEquivalent(Stmt *S1, Stmt *S2);
110 
111   /// Find the index of the given anonymous struct/union within its
112   /// context.
113   ///
114   /// \returns Returns the index of this anonymous struct/union in its context,
115   /// including the next assigned index (if none of them match). Returns an
116   /// empty option if the context is not a record, i.e.. if the anonymous
117   /// struct/union is at namespace or block scope.
118   ///
119   /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It
120   /// probably makes more sense in some other common place then here.
121   static std::optional<unsigned>
122   findUntaggedStructOrUnionIndex(RecordDecl *Anon);
123 
124   // If ErrorOnTagTypeMismatch is set, return the error, otherwise get the
125   // relevant warning for the input error diagnostic.
126   unsigned getApplicableDiagnostic(unsigned ErrorDiagnostic);
127 
128 private:
129   /// Finish checking all of the structural equivalences.
130   ///
131   /// \returns true if the equivalence check failed (non-equivalence detected),
132   /// false if equivalence was detected.
133   bool Finish();
134 
135   /// Check for common properties at Finish.
136   /// \returns true if D1 and D2 may be equivalent,
137   /// false if they are for sure not.
138   bool CheckCommonEquivalence(Decl *D1, Decl *D2);
139 
140   /// Check for class dependent properties at Finish.
141   /// \returns true if D1 and D2 may be equivalent,
142   /// false if they are for sure not.
143   bool CheckKindSpecificEquivalence(Decl *D1, Decl *D2);
144 };
145 
146 } // namespace clang
147 
148 #endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
149