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 
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   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)
FromCtxStructuralEquivalenceContext78       : 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   /// Determine whether the two statements are structurally 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(Stmt *S1, Stmt *S2);
106 
107   /// Find the index of the given anonymous struct/union within its
108   /// context.
109   ///
110   /// \returns Returns the index of this anonymous struct/union in its context,
111   /// including the next assigned index (if none of them match). Returns an
112   /// empty option if the context is not a record, i.e.. if the anonymous
113   /// struct/union is at namespace or block scope.
114   ///
115   /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It
116   /// probably makes more sense in some other common place then here.
117   static llvm::Optional<unsigned>
118   findUntaggedStructOrUnionIndex(RecordDecl *Anon);
119 
120   // If ErrorOnTagTypeMismatch is set, return the the error, otherwise get the
121   // relevant warning for the input error diagnostic.
122   unsigned getApplicableDiagnostic(unsigned ErrorDiagnostic);
123 
124 private:
125   /// Finish checking all of the structural equivalences.
126   ///
127   /// \returns true if the equivalence check failed (non-equivalence detected),
128   /// false if equivalence was detected.
129   bool Finish();
130 
131   /// Check for common properties at Finish.
132   /// \returns true if D1 and D2 may be equivalent,
133   /// false if they are for sure not.
134   bool CheckCommonEquivalence(Decl *D1, Decl *D2);
135 
136   /// Check for class dependent properties at Finish.
137   /// \returns true if D1 and D2 may be equivalent,
138   /// false if they are for sure not.
139   bool CheckKindSpecificEquivalence(Decl *D1, Decl *D2);
140 };
141 
142 } // namespace clang
143 
144 #endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
145