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, &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                             &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