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