Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 1 | //===--- Warnings.cpp - C-Language Front-end ------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // Command line warning options handler. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | // |
| 14 | // This file is responsible for handling all warning options. This includes |
| 15 | // a number of -Wfoo options and their variants, which are driven by TableGen- |
| 16 | // generated data, and the special cases -pedantic, -pedantic-errors, -w and |
| 17 | // -Werror. |
| 18 | // |
| 19 | // Warning options control the handling of the warnings that Clang emits. There |
| 20 | // are three possible reactions to any given warning: |
| 21 | // ignore: Do nothing |
| 22 | // warn: Emit a message, but don't fail the compilation |
| 23 | // error: Emit a message and fail the compilation |
| 24 | // |
Sebastian Redl | c5613db | 2009-03-07 12:09:25 +0000 | [diff] [blame] | 25 | // Each warning option controls any number of actual warnings. |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 26 | // Given a warning option 'foo', the following are valid: |
| 27 | // -Wfoo=ignore -> Ignore the controlled warnings. |
| 28 | // -Wfoo=warn -> Warn about the controlled warnings. |
| 29 | // -Wfoo=error -> Fail on the controlled warnings. |
| 30 | // -Wfoo -> alias of -Wfoo=warn |
| 31 | // -Wno-foo -> alias of -Wfoo=ignore |
| 32 | // -Werror=foo -> alias of -Wfoo=error |
| 33 | // |
| 34 | // Because of this complex handling of options, the default parser is replaced. |
| 35 | |
| 36 | #include "clang/Basic/Diagnostic.h" |
| 37 | #include "clang/Sema/SemaDiagnostic.h" |
| 38 | #include "clang/Lex/LexDiagnostic.h" |
| 39 | #include "llvm/Support/CommandLine.h" |
| 40 | #include <vector> |
| 41 | #include <string> |
| 42 | #include <utility> |
| 43 | #include <algorithm> |
| 44 | #include <string.h> |
| 45 | |
| 46 | using namespace clang; |
| 47 | |
| 48 | namespace { |
| 49 | struct ParsedOption { |
| 50 | std::string Name; |
| 51 | diag::Mapping Mapping; |
| 52 | |
| 53 | ParsedOption() {} |
| 54 | // Used by -Werror, implicitly. |
| 55 | ParsedOption(const std::string& name) : Name(name), Mapping(diag::MAP_ERROR) |
| 56 | {} |
| 57 | }; |
| 58 | |
| 59 | typedef std::vector<ParsedOption> OptionsList; |
| 60 | |
| 61 | OptionsList Options; |
| 62 | |
| 63 | struct WarningParser : public llvm::cl::basic_parser<ParsedOption> { |
| 64 | diag::Mapping StrToMapping(const std::string &S) { |
| 65 | if (S == "ignore") |
| 66 | return diag::MAP_IGNORE; |
| 67 | if (S == "warn") |
| 68 | return diag::MAP_WARNING; |
| 69 | if (S == "error") |
| 70 | return diag::MAP_ERROR; |
| 71 | return diag::MAP_DEFAULT; |
| 72 | } |
| 73 | bool parse(llvm::cl::Option &O, const char *ArgName, |
| 74 | const std::string &ArgValue, ParsedOption &Val) |
| 75 | { |
| 76 | size_t Eq = ArgValue.find("="); |
| 77 | if (Eq == std::string::npos) { |
| 78 | // Could be -Wfoo or -Wno-foo |
| 79 | if (ArgValue.compare(0, 3, "no-") == 0) { |
| 80 | Val.Name = ArgValue.substr(3); |
| 81 | Val.Mapping = diag::MAP_IGNORE; |
| 82 | } else { |
| 83 | Val.Name = ArgValue; |
| 84 | Val.Mapping = diag::MAP_WARNING; |
| 85 | } |
| 86 | } else { |
| 87 | Val.Name = ArgValue.substr(0, Eq); |
| 88 | Val.Mapping = StrToMapping(ArgValue.substr(Eq+1)); |
Sebastian Redl | c5613db | 2009-03-07 12:09:25 +0000 | [diff] [blame] | 89 | if (Val.Mapping == diag::MAP_DEFAULT) { |
| 90 | fprintf(stderr, "Illegal warning option value: %s\n", |
| 91 | ArgValue.substr(Eq+1).c_str()); |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 92 | return true; |
Sebastian Redl | c5613db | 2009-03-07 12:09:25 +0000 | [diff] [blame] | 93 | } |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 94 | } |
| 95 | return false; |
| 96 | } |
| 97 | }; |
| 98 | } |
| 99 | |
| 100 | static llvm::cl::list<ParsedOption, OptionsList, WarningParser> |
| 101 | OptWarnings("W", llvm::cl::location(Options), llvm::cl::Prefix); |
| 102 | |
| 103 | static llvm::cl::list<ParsedOption, OptionsList, llvm::cl::parser<std::string> > |
| 104 | OptWError("Werror", llvm::cl::location(Options), llvm::cl::CommaSeparated, |
| 105 | llvm::cl::ValueOptional); |
| 106 | |
| 107 | static llvm::cl::opt<bool> OptPedantic("pedantic"); |
| 108 | static llvm::cl::opt<bool> OptPedanticErrors("pedantic-errors"); |
| 109 | static llvm::cl::opt<bool> OptNoWarnings("w"); |
| 110 | static llvm::cl::opt<bool> |
Chris Lattner | db7bc58 | 2009-03-09 20:44:22 +0000 | [diff] [blame] | 111 | OptWarnInSystemHeaders("Wsystem-headers", |
| 112 | llvm::cl::desc("Do not suppress warnings issued in system headers")); |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 113 | |
| 114 | namespace { |
| 115 | struct WarningOption { |
| 116 | const char *Name; |
| 117 | const diag::kind *Members; |
| 118 | size_t NumMembers; |
| 119 | }; |
| 120 | bool operator <(const WarningOption& lhs, const WarningOption& rhs) { |
| 121 | return strcmp(lhs.Name, rhs.Name) < 0; |
| 122 | } |
| 123 | } |
| 124 | #define DIAGS(a) a, (sizeof(a) / sizeof(a[0])) |
| 125 | // These tables will be TableGenerated later. |
| 126 | // First the table sets describing the diagnostics controlled by each option. |
| 127 | static const diag::kind UnusedMacrosDiags[] = { diag::pp_macro_not_used }; |
| 128 | static const diag::kind FloatEqualDiags[] = { diag::warn_floatingpoint_eq }; |
| 129 | static const diag::kind ReadOnlySetterAttrsDiags[] = { |
| 130 | diag::warn_objc_property_attr_mutually_exclusive |
| 131 | }; |
| 132 | static const diag::kind FormatNonLiteralDiags[] = { |
| 133 | diag::warn_printf_not_string_constant |
| 134 | }; |
| 135 | static const diag::kind UndefDiags[] = { diag::warn_pp_undef_identifier }; |
| 136 | static const diag::kind ImplicitFunctionDeclarationDiags[] = { |
| 137 | diag::ext_implicit_function_decl, diag::warn_implicit_function_decl |
| 138 | }; |
| 139 | // Hmm ... this option is currently actually completely ignored. |
| 140 | //static const diag::kind StrictSelectorMatchDiags[] = { }; |
| 141 | // Second the table of options. MUST be sorted by name! Binary lookup is done. |
| 142 | static const WarningOption OptionTable[] = { |
| 143 | { "float-equal", DIAGS(FloatEqualDiags) }, |
| 144 | { "format-nonliteral", DIAGS(FormatNonLiteralDiags) }, |
| 145 | { "implicit-function-declaration", DIAGS(ImplicitFunctionDeclarationDiags) }, |
| 146 | { "readonly-setter-attrs", DIAGS(ReadOnlySetterAttrsDiags) }, |
| 147 | { "undef", DIAGS(UndefDiags) }, |
| 148 | { "unused-macros", DIAGS(UnusedMacrosDiags) }, |
| 149 | // { "strict-selector-match", DIAGS(StrictSelectorMatchDiags) } |
| 150 | }; |
| 151 | static const size_t OptionTableSize = |
| 152 | sizeof(OptionTable) / sizeof(OptionTable[0]); |
| 153 | |
| 154 | namespace clang { |
| 155 | |
| 156 | bool ProcessWarningOptions(Diagnostic &Diags) { |
| 157 | // FIXME: These should be mapped to group options. |
| 158 | Diags.setIgnoreAllWarnings(OptNoWarnings); |
| 159 | Diags.setWarnOnExtensions(OptPedantic); |
| 160 | Diags.setErrorOnExtensions(OptPedanticErrors); |
| 161 | |
| 162 | // Set some defaults that are currently set manually. This, too, should |
| 163 | // be in the tablegen stuff later. |
| 164 | Diags.setDiagnosticMapping(diag::pp_macro_not_used, diag::MAP_IGNORE); |
| 165 | Diags.setDiagnosticMapping(diag::warn_floatingpoint_eq, diag::MAP_IGNORE); |
| 166 | Diags.setDiagnosticMapping(diag::warn_objc_property_attr_mutually_exclusive, |
| 167 | diag::MAP_IGNORE); |
| 168 | Diags.setDiagnosticMapping(diag::warn_pp_undef_identifier, diag::MAP_IGNORE); |
| 169 | Diags.setDiagnosticMapping(diag::warn_implicit_function_decl, |
| 170 | diag::MAP_IGNORE); |
| 171 | |
| 172 | Diags.setDiagnosticMapping(diag::err_pp_file_not_found, diag::MAP_FATAL); |
Chris Lattner | db7bc58 | 2009-03-09 20:44:22 +0000 | [diff] [blame] | 173 | Diags.setSuppressSystemWarnings(!OptWarnInSystemHeaders); |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 174 | |
| 175 | for (OptionsList::iterator it = Options.begin(), e = Options.end(); |
| 176 | it != e; ++it) { |
| 177 | if (it->Name.empty()) { |
| 178 | // Empty string is "everything". This way, -Werror does the right thing. |
| 179 | // FIXME: These flags do not participate in proper option overriding. |
| 180 | switch(it->Mapping) { |
| 181 | default: |
| 182 | assert(false && "Illegal mapping"); |
| 183 | break; |
| 184 | |
| 185 | case diag::MAP_IGNORE: |
| 186 | Diags.setIgnoreAllWarnings(true); |
| 187 | Diags.setWarningsAsErrors(false); |
| 188 | break; |
| 189 | |
| 190 | case diag::MAP_WARNING: |
| 191 | Diags.setIgnoreAllWarnings(false); |
| 192 | Diags.setWarningsAsErrors(false); |
| 193 | break; |
| 194 | |
| 195 | case diag::MAP_ERROR: |
| 196 | Diags.setIgnoreAllWarnings(false); |
| 197 | Diags.setWarningsAsErrors(true); |
| 198 | break; |
| 199 | } |
| 200 | continue; |
| 201 | } |
| 202 | WarningOption Key = { it->Name.c_str(), 0, 0 }; |
| 203 | const WarningOption *Found = std::lower_bound(OptionTable, |
| 204 | OptionTable + OptionTableSize, |
| 205 | Key); |
| 206 | if (Found == OptionTable + OptionTableSize || |
Sebastian Redl | c5613db | 2009-03-07 12:09:25 +0000 | [diff] [blame] | 207 | strcmp(Found->Name, Key.Name) != 0) { |
| 208 | fprintf(stderr, "Unknown warning option: -W%s\n", Key.Name); |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 209 | return true; |
Sebastian Redl | c5613db | 2009-03-07 12:09:25 +0000 | [diff] [blame] | 210 | } |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 211 | |
| 212 | // Option exists. |
| 213 | for (size_t i = 0; i < Found->NumMembers; ++i) { |
| 214 | Diags.setDiagnosticMapping(Found->Members[i], it->Mapping); |
| 215 | } |
| 216 | } |
| 217 | return false; |
| 218 | } |
| 219 | |
| 220 | } |