1 | //===- ODRDiagsEmitter.h - Emits diagnostic for ODR mismatches --*- 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 | #ifndef LLVM_CLANG_AST_ODRDIAGSEMITTER_H |
10 | #define LLVM_CLANG_AST_ODRDIAGSEMITTER_H |
11 | |
12 | #include "clang/AST/ASTContext.h" |
13 | #include "clang/AST/DeclCXX.h" |
14 | #include "clang/AST/DeclObjC.h" |
15 | #include "clang/Basic/Diagnostic.h" |
16 | #include "clang/Basic/LangOptions.h" |
17 | |
18 | namespace clang { |
19 | |
20 | class ODRDiagsEmitter { |
21 | public: |
22 | ODRDiagsEmitter(DiagnosticsEngine &Diags, const ASTContext &Context, |
23 | const LangOptions &LangOpts) |
24 | : Diags(Diags), Context(Context), LangOpts(LangOpts) {} |
25 | |
26 | /// Diagnose ODR mismatch between 2 FunctionDecl. |
27 | /// |
28 | /// Returns true if found a mismatch and diagnosed it. |
29 | bool diagnoseMismatch(const FunctionDecl *FirstFunction, |
30 | const FunctionDecl *SecondFunction) const; |
31 | |
32 | /// Diagnose ODR mismatch between 2 EnumDecl. |
33 | /// |
34 | /// Returns true if found a mismatch and diagnosed it. |
35 | bool diagnoseMismatch(const EnumDecl *FirstEnum, |
36 | const EnumDecl *SecondEnum) const; |
37 | |
38 | /// Diagnose ODR mismatch between 2 CXXRecordDecl. |
39 | /// |
40 | /// Returns true if found a mismatch and diagnosed it. |
41 | /// To compare 2 declarations with merged and identical definition data |
42 | /// you need to provide pre-merge definition data in \p SecondDD. |
43 | bool |
44 | diagnoseMismatch(const CXXRecordDecl *FirstRecord, |
45 | const CXXRecordDecl *SecondRecord, |
46 | const struct CXXRecordDecl::DefinitionData *SecondDD) const; |
47 | |
48 | /// Diagnose ODR mismatch between 2 RecordDecl that are not CXXRecordDecl. |
49 | /// |
50 | /// Returns true if found a mismatch and diagnosed it. |
51 | bool diagnoseMismatch(const RecordDecl *FirstRecord, |
52 | const RecordDecl *SecondRecord) const; |
53 | |
54 | /// Diagnose ODR mismatch between 2 ObjCInterfaceDecl. |
55 | /// |
56 | /// Returns true if found a mismatch and diagnosed it. |
57 | bool diagnoseMismatch( |
58 | const ObjCInterfaceDecl *FirstID, const ObjCInterfaceDecl *SecondID, |
59 | const struct ObjCInterfaceDecl::DefinitionData *SecondDD) const; |
60 | |
61 | /// Diagnose ODR mismatch between ObjCInterfaceDecl with different |
62 | /// definitions. |
63 | bool diagnoseMismatch(const ObjCInterfaceDecl *FirstID, |
64 | const ObjCInterfaceDecl *SecondID) const { |
65 | assert(FirstID->data().Definition != SecondID->data().Definition && |
66 | "Don't diagnose differences when definitions are merged already" ); |
67 | return diagnoseMismatch(FirstID, SecondID, SecondDD: &SecondID->data()); |
68 | } |
69 | |
70 | /// Diagnose ODR mismatch between 2 ObjCProtocolDecl. |
71 | /// |
72 | /// Returns true if found a mismatch and diagnosed it. |
73 | /// To compare 2 declarations with merged and identical definition data |
74 | /// you need to provide pre-merge definition data in \p SecondDD. |
75 | bool diagnoseMismatch( |
76 | const ObjCProtocolDecl *FirstProtocol, |
77 | const ObjCProtocolDecl *SecondProtocol, |
78 | const struct ObjCProtocolDecl::DefinitionData *SecondDD) const; |
79 | |
80 | /// Diagnose ODR mismatch between ObjCProtocolDecl with different definitions. |
81 | bool diagnoseMismatch(const ObjCProtocolDecl *FirstProtocol, |
82 | const ObjCProtocolDecl *SecondProtocol) const { |
83 | assert(FirstProtocol->data().Definition != |
84 | SecondProtocol->data().Definition && |
85 | "Don't diagnose differences when definitions are merged already" ); |
86 | return diagnoseMismatch(FirstProtocol, SecondProtocol, |
87 | SecondDD: &SecondProtocol->data()); |
88 | } |
89 | |
90 | /// Get the best name we know for the module that owns the given |
91 | /// declaration, or an empty string if the declaration is not from a module. |
92 | static std::string getOwningModuleNameForDiagnostic(const Decl *D); |
93 | |
94 | private: |
95 | using DeclHashes = llvm::SmallVector<std::pair<const Decl *, unsigned>, 4>; |
96 | |
97 | // Used with err_module_odr_violation_mismatch_decl, |
98 | // note_module_odr_violation_mismatch_decl, |
99 | // err_module_odr_violation_mismatch_decl_unknown, |
100 | // and note_module_odr_violation_mismatch_decl_unknown |
101 | // This list should be the same Decl's as in ODRHash::isSubDeclToBeProcessed |
102 | enum ODRMismatchDecl { |
103 | EndOfClass, |
104 | PublicSpecifer, |
105 | PrivateSpecifer, |
106 | ProtectedSpecifer, |
107 | StaticAssert, |
108 | Field, |
109 | CXXMethod, |
110 | TypeAlias, |
111 | TypeDef, |
112 | Var, |
113 | Friend, |
114 | FunctionTemplate, |
115 | ObjCMethod, |
116 | ObjCIvar, |
117 | ObjCProperty, |
118 | Other |
119 | }; |
120 | |
121 | struct DiffResult { |
122 | const Decl *FirstDecl = nullptr, *SecondDecl = nullptr; |
123 | ODRMismatchDecl FirstDiffType = Other, SecondDiffType = Other; |
124 | }; |
125 | |
126 | // If there is a diagnoseable difference, FirstDiffType and |
127 | // SecondDiffType will not be Other and FirstDecl and SecondDecl will be |
128 | // filled in if not EndOfClass. |
129 | static DiffResult FindTypeDiffs(DeclHashes &FirstHashes, |
130 | DeclHashes &SecondHashes); |
131 | |
132 | DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const { |
133 | return Diags.Report(Loc, DiagID); |
134 | } |
135 | |
136 | // Use this to diagnose that an unexpected Decl was encountered |
137 | // or no difference was detected. This causes a generic error |
138 | // message to be emitted. |
139 | void diagnoseSubMismatchUnexpected(DiffResult &DR, |
140 | const NamedDecl *FirstRecord, |
141 | StringRef FirstModule, |
142 | const NamedDecl *SecondRecord, |
143 | StringRef SecondModule) const; |
144 | |
145 | void diagnoseSubMismatchDifferentDeclKinds(DiffResult &DR, |
146 | const NamedDecl *FirstRecord, |
147 | StringRef FirstModule, |
148 | const NamedDecl *SecondRecord, |
149 | StringRef SecondModule) const; |
150 | |
151 | bool diagnoseSubMismatchField(const NamedDecl *FirstRecord, |
152 | StringRef FirstModule, StringRef SecondModule, |
153 | const FieldDecl *FirstField, |
154 | const FieldDecl *SecondField) const; |
155 | |
156 | bool diagnoseSubMismatchTypedef(const NamedDecl *FirstRecord, |
157 | StringRef FirstModule, StringRef SecondModule, |
158 | const TypedefNameDecl *FirstTD, |
159 | const TypedefNameDecl *SecondTD, |
160 | bool IsTypeAlias) const; |
161 | |
162 | bool diagnoseSubMismatchVar(const NamedDecl *FirstRecord, |
163 | StringRef FirstModule, StringRef SecondModule, |
164 | const VarDecl *FirstVD, |
165 | const VarDecl *SecondVD) const; |
166 | |
167 | /// Check if protocol lists are the same and diagnose if they are different. |
168 | /// |
169 | /// Returns true if found a mismatch and diagnosed it. |
170 | bool diagnoseSubMismatchProtocols(const ObjCProtocolList &FirstProtocols, |
171 | const ObjCContainerDecl *FirstContainer, |
172 | StringRef FirstModule, |
173 | const ObjCProtocolList &SecondProtocols, |
174 | const ObjCContainerDecl *SecondContainer, |
175 | StringRef SecondModule) const; |
176 | |
177 | /// Check if Objective-C methods are the same and diagnose if different. |
178 | /// |
179 | /// Returns true if found a mismatch and diagnosed it. |
180 | bool diagnoseSubMismatchObjCMethod(const NamedDecl *FirstObjCContainer, |
181 | StringRef FirstModule, |
182 | StringRef SecondModule, |
183 | const ObjCMethodDecl *FirstMethod, |
184 | const ObjCMethodDecl *SecondMethod) const; |
185 | |
186 | /// Check if Objective-C properties are the same and diagnose if different. |
187 | /// |
188 | /// Returns true if found a mismatch and diagnosed it. |
189 | bool |
190 | diagnoseSubMismatchObjCProperty(const NamedDecl *FirstObjCContainer, |
191 | StringRef FirstModule, StringRef SecondModule, |
192 | const ObjCPropertyDecl *FirstProp, |
193 | const ObjCPropertyDecl *SecondProp) const; |
194 | |
195 | private: |
196 | DiagnosticsEngine &Diags; |
197 | const ASTContext &Context; |
198 | const LangOptions &LangOpts; |
199 | }; |
200 | |
201 | } // namespace clang |
202 | |
203 | #endif |
204 | |