xref: /llvm-project/clang/include/clang/AST/ASTStructuralEquivalence.h (revision 7a1fdbb9c0f3becdbe539f0518d182f56a9f99f8)
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   /// Store declaration pairs already found to be non-equivalent.
43   /// key: (from, to, IgnoreTemplateParmDepth)
44   using NonEquivalentDeclSet = llvm::DenseSet<std::tuple<Decl *, Decl *, int>>;
45 
46   /// AST contexts for which we are checking structural equivalence.
47   ASTContext &FromCtx, &ToCtx;
48 
49   // Queue of from-to Decl pairs that are to be checked to determine the final
50   // result of equivalence of a starting Decl pair.
51   std::queue<std::pair<Decl *, Decl *>> DeclsToCheck;
52 
53   // Set of from-to Decl pairs that are already visited during the check
54   // (are in or were once in \c DeclsToCheck) of a starting Decl pair.
55   llvm::DenseSet<std::pair<Decl *, Decl *>> VisitedDecls;
56 
57   /// Declaration (from, to) pairs that are known not to be equivalent
58   /// (which we have already complained about).
59   NonEquivalentDeclSet &NonEquivalentDecls;
60 
61   StructuralEquivalenceKind EqKind;
62 
63   /// Whether we're being strict about the spelling of types when
64   /// unifying two types.
65   bool StrictTypeSpelling;
66 
67   /// Whether warn or error on tag type mismatches.
68   bool ErrorOnTagTypeMismatch;
69 
70   /// Whether to complain about failures.
71   bool Complain;
72 
73   /// \c true if the last diagnostic came from ToCtx.
74   bool LastDiagFromC2 = false;
75 
76   /// Whether to ignore comparing the depth of template param(TemplateTypeParm)
77   bool IgnoreTemplateParmDepth;
78 
79   StructuralEquivalenceContext(ASTContext &FromCtx, ASTContext &ToCtx,
80                                NonEquivalentDeclSet &NonEquivalentDecls,
81                                StructuralEquivalenceKind EqKind,
82                                bool StrictTypeSpelling = false,
83                                bool Complain = true,
84                                bool ErrorOnTagTypeMismatch = false,
85                                bool IgnoreTemplateParmDepth = false)
86       : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls),
87         EqKind(EqKind), StrictTypeSpelling(StrictTypeSpelling),
88         ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain),
89         IgnoreTemplateParmDepth(IgnoreTemplateParmDepth) {}
90 
91   DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID);
92   DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID);
93 
94   /// Determine whether the two declarations are structurally
95   /// equivalent.
96   /// Implementation functions (all static functions in
97   /// ASTStructuralEquivalence.cpp) must never call this function because that
98   /// will wreak havoc the internal state (\c DeclsToCheck and
99   /// \c VisitedDecls members) and can cause faulty equivalent results.
100   bool IsEquivalent(Decl *D1, Decl *D2);
101 
102   /// Determine whether the two types are structurally equivalent.
103   /// Implementation functions (all static functions in
104   /// ASTStructuralEquivalence.cpp) must never call this function because that
105   /// will wreak havoc the internal state (\c DeclsToCheck and
106   /// \c VisitedDecls members) and can cause faulty equivalent results.
107   bool IsEquivalent(QualType T1, QualType T2);
108 
109   /// Determine whether the two statements are structurally equivalent.
110   /// Implementation functions (all static functions in
111   /// ASTStructuralEquivalence.cpp) must never call this function because that
112   /// will wreak havoc the internal state (\c DeclsToCheck and
113   /// \c VisitedDecls members) and can cause faulty equivalent results.
114   bool IsEquivalent(Stmt *S1, Stmt *S2);
115 
116   /// Find the index of the given anonymous struct/union within its
117   /// context.
118   ///
119   /// \returns Returns the index of this anonymous struct/union in its context,
120   /// including the next assigned index (if none of them match). Returns an
121   /// empty option if the context is not a record, i.e.. if the anonymous
122   /// struct/union is at namespace or block scope.
123   ///
124   /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It
125   /// probably makes more sense in some other common place then here.
126   static std::optional<unsigned>
127   findUntaggedStructOrUnionIndex(RecordDecl *Anon);
128 
129   // If ErrorOnTagTypeMismatch is set, return the error, otherwise get the
130   // relevant warning for the input error diagnostic.
131   unsigned getApplicableDiagnostic(unsigned ErrorDiagnostic);
132 
133 private:
134   /// Finish checking all of the structural equivalences.
135   ///
136   /// \returns true if the equivalence check failed (non-equivalence detected),
137   /// false if equivalence was detected.
138   bool Finish();
139 
140   /// Check for common properties at Finish.
141   /// \returns true if D1 and D2 may be equivalent,
142   /// false if they are for sure not.
143   bool CheckCommonEquivalence(Decl *D1, Decl *D2);
144 
145   /// Check for class dependent properties at Finish.
146   /// \returns true if D1 and D2 may be equivalent,
147   /// false if they are for sure not.
148   bool CheckKindSpecificEquivalence(Decl *D1, Decl *D2);
149 };
150 
151 } // namespace clang
152 
153 #endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
154