1252190Srpaulo//===- ODRDiagsEmitter.h - Emits diagnostic for ODR mismatches --*- C++ -*-===//
2252190Srpaulo//
3252190Srpaulo// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4252190Srpaulo// See https://llvm.org/LICENSE.txt for license information.
5252190Srpaulo// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6252190Srpaulo//
7252190Srpaulo//===----------------------------------------------------------------------===//
8252190Srpaulo
9252190Srpaulo#ifndef LLVM_CLANG_AST_ODRDIAGSEMITTER_H
10252190Srpaulo#define LLVM_CLANG_AST_ODRDIAGSEMITTER_H
11252190Srpaulo
12252190Srpaulo#include "clang/AST/ASTContext.h"
13252190Srpaulo#include "clang/AST/DeclCXX.h"
14252190Srpaulo#include "clang/AST/DeclObjC.h"
15252190Srpaulo#include "clang/Basic/Diagnostic.h"
16252190Srpaulo#include "clang/Basic/LangOptions.h"
17
18namespace clang {
19
20class ODRDiagsEmitter {
21public:
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
94private:
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
195private:
196  DiagnosticsEngine &Diags;
197  const ASTContext &Context;
198  const LangOptions &LangOpts;
199};
200
201} // namespace clang
202
203#endif
204