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: ODRDiagsEmitter(DiagnosticsEngine & Diags,const ASTContext & Context,const LangOptions & LangOpts)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. diagnoseMismatch(const ObjCInterfaceDecl * FirstID,const ObjCInterfaceDecl * SecondID)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. diagnoseMismatch(const ObjCProtocolDecl * FirstProtocol,const ObjCProtocolDecl * SecondProtocol)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 Diag(SourceLocation Loc,unsigned DiagID)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