1193326Sed//===--- Warnings.cpp - C-Language Front-end ------------------------------===//
2193326Sed//
3193326Sed//                     The LLVM Compiler Infrastructure
4193326Sed//
5193326Sed// This file is distributed under the University of Illinois Open Source
6193326Sed// License. See LICENSE.TXT for details.
7193326Sed//
8193326Sed//===----------------------------------------------------------------------===//
9193326Sed//
10193326Sed// Command line warning options handler.
11193326Sed//
12193326Sed//===----------------------------------------------------------------------===//
13193326Sed//
14193326Sed// This file is responsible for handling all warning options. This includes
15193326Sed// a number of -Wfoo options and their variants, which are driven by TableGen-
16201361Srdivacky// generated data, and the special cases -pedantic, -pedantic-errors, -w,
17201361Srdivacky// -Werror and -Wfatal-errors.
18193326Sed//
19193326Sed// Each warning option controls any number of actual warnings.
20193326Sed// Given a warning option 'foo', the following are valid:
21201361Srdivacky//    -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo
22193326Sed//
23193326Sed#include "clang/Frontend/Utils.h"
24193326Sed#include "clang/Basic/Diagnostic.h"
25243830Sdim#include "clang/Basic/DiagnosticOptions.h"
26194711Sed#include "clang/Frontend/FrontendDiagnostic.h"
27249423Sdim#include "clang/Lex/LexDiagnostic.h"
28249423Sdim#include "clang/Sema/SemaDiagnostic.h"
29249423Sdim#include <algorithm>
30193326Sed#include <cstring>
31193326Sed#include <utility>
32193326Sedusing namespace clang;
33193326Sed
34234353Sdim// EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning
35234353Sdim// opts
36234353Sdimstatic void EmitUnknownDiagWarning(DiagnosticsEngine &Diags,
37234353Sdim                                  StringRef Prefix, StringRef Opt,
38234353Sdim                                  bool isPositive) {
39234353Sdim  StringRef Suggestion = DiagnosticIDs::getNearestWarningOption(Opt);
40234353Sdim  if (!Suggestion.empty())
41234353Sdim    Diags.Report(isPositive? diag::warn_unknown_warning_option_suggest :
42234353Sdim                             diag::warn_unknown_negative_warning_option_suggest)
43234353Sdim      << (Prefix.str() += Opt) << (Prefix.str() += Suggestion);
44234353Sdim  else
45234353Sdim    Diags.Report(isPositive? diag::warn_unknown_warning_option :
46234353Sdim                             diag::warn_unknown_negative_warning_option)
47234353Sdim      << (Prefix.str() += Opt);
48234353Sdim}
49234353Sdim
50226633Sdimvoid clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
51249423Sdim                                  const DiagnosticOptions &Opts,
52249423Sdim                                  bool ReportDiags) {
53193326Sed  Diags.setSuppressSystemWarnings(true);  // Default to -Wno-system-headers
54199482Srdivacky  Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
55243830Sdim  Diags.setShowOverloads(Opts.getShowOverloads());
56239462Sdim
57239462Sdim  Diags.setElideType(Opts.ElideType);
58239462Sdim  Diags.setPrintTemplateTree(Opts.ShowTemplateTree);
59239462Sdim  Diags.setShowColors(Opts.ShowColors);
60239462Sdim
61207619Srdivacky  // Handle -ferror-limit
62207619Srdivacky  if (Opts.ErrorLimit)
63207619Srdivacky    Diags.setErrorLimit(Opts.ErrorLimit);
64207619Srdivacky  if (Opts.TemplateBacktraceLimit)
65207619Srdivacky    Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit);
66234353Sdim  if (Opts.ConstexprBacktraceLimit)
67234353Sdim    Diags.setConstexprBacktraceLimit(Opts.ConstexprBacktraceLimit);
68193326Sed
69193326Sed  // If -pedantic or -pedantic-errors was specified, then we want to map all
70193326Sed  // extension diagnostics onto WARNING or ERROR unless the user has futz'd
71193326Sed  // around with them explicitly.
72199482Srdivacky  if (Opts.PedanticErrors)
73226633Sdim    Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Error);
74199482Srdivacky  else if (Opts.Pedantic)
75226633Sdim    Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Warn);
76193326Sed  else
77226633Sdim    Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Ignore);
78198092Srdivacky
79249423Sdim  SmallVector<diag::kind, 10> _Diags;
80234353Sdim  const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs =
81234353Sdim    Diags.getDiagnosticIDs();
82234353Sdim  // We parse the warning options twice.  The first pass sets diagnostic state,
83234353Sdim  // while the second pass reports warnings/errors.  This has the effect that
84234353Sdim  // we follow the more canonical "last option wins" paradigm when there are
85234353Sdim  // conflicting options.
86234353Sdim  for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) {
87234353Sdim    bool SetDiagnostic = (Report == 0);
88249423Sdim
89249423Sdim    // If we've set the diagnostic state and are not reporting diagnostics then
90249423Sdim    // we're done.
91249423Sdim    if (!SetDiagnostic && !ReportDiags)
92249423Sdim      break;
93249423Sdim
94234353Sdim    for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
95234353Sdim      StringRef Opt = Opts.Warnings[i];
96239462Sdim      StringRef OrigOpt = Opts.Warnings[i];
97198092Srdivacky
98234353Sdim      // Treat -Wformat=0 as an alias for -Wno-format.
99234353Sdim      if (Opt == "format=0")
100234353Sdim        Opt = "no-format";
101193326Sed
102234353Sdim      // Check to see if this warning starts with "no-", if so, this is a
103234353Sdim      // negative form of the option.
104234353Sdim      bool isPositive = true;
105234353Sdim      if (Opt.startswith("no-")) {
106234353Sdim        isPositive = false;
107234353Sdim        Opt = Opt.substr(3);
108193326Sed      }
109198092Srdivacky
110234353Sdim      // Figure out how this option affects the warning.  If -Wfoo, map the
111234353Sdim      // diagnostic to a warning, if -Wno-foo, map it to ignore.
112234353Sdim      diag::Mapping Mapping = isPositive ? diag::MAP_WARNING : diag::MAP_IGNORE;
113234353Sdim
114234353Sdim      // -Wsystem-headers is a special case, not driven by the option table.  It
115234353Sdim      // cannot be controlled with -Werror.
116234353Sdim      if (Opt == "system-headers") {
117234353Sdim        if (SetDiagnostic)
118234353Sdim          Diags.setSuppressSystemWarnings(!isPositive);
119193326Sed        continue;
120193326Sed      }
121234353Sdim
122234353Sdim      // -Weverything is a special case as well.  It implicitly enables all
123234353Sdim      // warnings, including ones not explicitly in a warning group.
124234353Sdim      if (Opt == "everything") {
125234353Sdim        if (SetDiagnostic) {
126234353Sdim          if (isPositive) {
127234353Sdim            Diags.setEnableAllWarnings(true);
128234353Sdim          } else {
129234353Sdim            Diags.setEnableAllWarnings(false);
130234353Sdim            Diags.setMappingToAllDiagnostics(diag::MAP_IGNORE);
131234353Sdim          }
132234353Sdim        }
133234353Sdim        continue;
134226633Sdim      }
135234353Sdim
136234353Sdim      // -Werror/-Wno-error is a special case, not controlled by the option
137234353Sdim      // table. It also has the "specifier" form of -Werror=foo and -Werror-foo.
138234353Sdim      if (Opt.startswith("error")) {
139234353Sdim        StringRef Specifier;
140234353Sdim        if (Opt.size() > 5) {  // Specifier must be present.
141234353Sdim          if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) {
142234353Sdim            if (Report)
143234353Sdim              Diags.Report(diag::warn_unknown_warning_specifier)
144239462Sdim                << "-Werror" << ("-W" + OrigOpt.str());
145234353Sdim            continue;
146234353Sdim          }
147234353Sdim          Specifier = Opt.substr(6);
148234353Sdim        }
149234353Sdim
150234353Sdim        if (Specifier.empty()) {
151234353Sdim          if (SetDiagnostic)
152234353Sdim            Diags.setWarningsAsErrors(isPositive);
153201361Srdivacky          continue;
154201361Srdivacky        }
155234353Sdim
156234353Sdim        if (SetDiagnostic) {
157234353Sdim          // Set the warning as error flag for this specifier.
158234353Sdim          Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive);
159234353Sdim        } else if (DiagIDs->getDiagnosticsInGroup(Specifier, _Diags)) {
160234353Sdim          EmitUnknownDiagWarning(Diags, "-Werror=", Specifier, isPositive);
161234353Sdim        }
162234353Sdim        continue;
163201361Srdivacky      }
164234353Sdim
165234353Sdim      // -Wfatal-errors is yet another special case.
166234353Sdim      if (Opt.startswith("fatal-errors")) {
167234353Sdim        StringRef Specifier;
168234353Sdim        if (Opt.size() != 12) {
169234353Sdim          if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) {
170234353Sdim            if (Report)
171234353Sdim              Diags.Report(diag::warn_unknown_warning_specifier)
172239462Sdim                << "-Wfatal-errors" << ("-W" + OrigOpt.str());
173234353Sdim            continue;
174234353Sdim          }
175234353Sdim          Specifier = Opt.substr(13);
176234353Sdim        }
177201361Srdivacky
178234353Sdim        if (Specifier.empty()) {
179234353Sdim          if (SetDiagnostic)
180234353Sdim            Diags.setErrorsAsFatal(isPositive);
181234353Sdim          continue;
182234353Sdim        }
183234353Sdim
184234353Sdim        if (SetDiagnostic) {
185234353Sdim          // Set the error as fatal flag for this specifier.
186234353Sdim          Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive);
187234353Sdim        } else if (DiagIDs->getDiagnosticsInGroup(Specifier, _Diags)) {
188234353Sdim          EmitUnknownDiagWarning(Diags, "-Wfatal-errors=", Specifier,
189234353Sdim                                 isPositive);
190234353Sdim        }
191201361Srdivacky        continue;
192201361Srdivacky      }
193234353Sdim
194234353Sdim      if (Report) {
195234353Sdim        if (DiagIDs->getDiagnosticsInGroup(Opt, _Diags))
196239462Sdim          EmitUnknownDiagWarning(Diags, isPositive ? "-W" : "-Wno-", Opt,
197239462Sdim                                 isPositive);
198234353Sdim      } else {
199234353Sdim        Diags.setDiagnosticGroupMapping(Opt, Mapping);
200226633Sdim      }
201201361Srdivacky    }
202193326Sed  }
203193326Sed}
204