| Index: tools/clang/plugins/FindBadConstructsConsumer.cpp
 | 
| diff --git a/tools/clang/plugins/FindBadConstructsConsumer.cpp b/tools/clang/plugins/FindBadConstructsConsumer.cpp
 | 
| index 770e2551d6e7c92f12032f850251ba5b8af738d1..20919a41afd7afb98a90211160b36d23cccacac7 100644
 | 
| --- a/tools/clang/plugins/FindBadConstructsConsumer.cpp
 | 
| +++ b/tools/clang/plugins/FindBadConstructsConsumer.cpp
 | 
| @@ -70,14 +70,15 @@ bool IsGtestTestFixture(const CXXRecordDecl* decl) {
 | 
|    return decl->getQualifiedNameAsString() == "testing::Test";
 | 
|  }
 | 
|  
 | 
| +// Generates a fixit hint to remove the 'virtual' keyword.
 | 
| +// Unfortunately, there doesn't seem to be a good way to determine the source
 | 
| +// location of the 'virtual' keyword. It's available in Declarator, but that
 | 
| +// isn't accessible from the AST. So instead, make an educated guess that the
 | 
| +// first token is probably the virtual keyword. Strictly speaking, this doesn't
 | 
| +// have to be true, but it probably will be.
 | 
| +// TODO(dcheng): Add a warning to force virtual to always appear first ;-)
 | 
|  FixItHint FixItRemovalForVirtual(const SourceManager& manager,
 | 
|                                   const CXXMethodDecl* method) {
 | 
| -  // Unfortunately, there doesn't seem to be a good way to determine the
 | 
| -  // location of the 'virtual' keyword. It's available in Declarator, but that
 | 
| -  // isn't accessible from the AST. So instead, make an educated guess that the
 | 
| -  // first token is probably the virtual keyword. Strictly speaking, this
 | 
| -  // doesn't have to be true, but it probably will be.
 | 
| -  // TODO(dcheng): Add a warning to force virtual to always appear first ;-)
 | 
|    SourceRange range(method->getLocStart());
 | 
|    // Get the spelling loc just in case it was expanded from a macro.
 | 
|    SourceRange spelling_range(manager.getSpellingLoc(range.getBegin()));
 | 
| @@ -413,32 +414,68 @@ void FindBadConstructsConsumer::CheckVirtualSpecifiers(
 | 
|  
 | 
|    // Complain if a method is annotated virtual && (override || final).
 | 
|    if (has_virtual && (override_attr || final_attr)) {
 | 
| -    diagnostic().Report(method->getLocStart(),
 | 
| -                        diag_redundant_virtual_specifier_)
 | 
| -        << "'virtual'"
 | 
| -        << (override_attr ? static_cast<Attr*>(override_attr) : final_attr)
 | 
| -        << FixItRemovalForVirtual(manager, method);
 | 
| +    // ... but only if virtual does not originate in a macro from a banned file.
 | 
| +    // Note this is just an educated guess: the assumption here is that any
 | 
| +    // macro for declaring methods will probably be at the start of the method's
 | 
| +    // source range.
 | 
| +    if (!InBannedDirectory(manager.getSpellingLoc(method->getLocStart()))) {
 | 
| +      diagnostic().Report(method->getLocStart(),
 | 
| +                          diag_redundant_virtual_specifier_)
 | 
| +          << "'virtual'"
 | 
| +          << (override_attr ? static_cast<Attr*>(override_attr) : final_attr)
 | 
| +          << FixItRemovalForVirtual(manager, method);
 | 
| +    }
 | 
|    }
 | 
|  
 | 
|    // Complain if a method is an override and is not annotated with override or
 | 
|    // final.
 | 
|    if (is_override && !override_attr && !final_attr) {
 | 
| -    SourceRange type_info_range =
 | 
| -        method->getTypeSourceInfo()->getTypeLoc().getSourceRange();
 | 
| -    FullSourceLoc loc(type_info_range.getBegin(), manager);
 | 
| -
 | 
| -    // Build the FixIt insertion point after the end of the method definition,
 | 
| -    // including any const-qualifiers and attributes, and before the opening
 | 
| -    // of the l-curly-brace (if inline) or the semi-color (if a declaration).
 | 
| -    SourceLocation spelling_end =
 | 
| -        manager.getSpellingLoc(type_info_range.getEnd());
 | 
| -    if (spelling_end.isValid()) {
 | 
| -      SourceLocation token_end =
 | 
| -          Lexer::getLocForEndOfToken(spelling_end, 0, manager, LangOptions());
 | 
| -      diagnostic().Report(token_end, diag_method_requires_override_)
 | 
| -          << FixItHint::CreateInsertion(token_end, " override");
 | 
| +    SourceRange range = method->getSourceRange();
 | 
| +    SourceLocation loc;
 | 
| +    if (method->hasInlineBody()) {
 | 
| +      loc = method->getBody()->getSourceRange().getBegin();
 | 
| +    } else {
 | 
| +      // TODO(dcheng): We should probably use ASTContext's LangOptions here.
 | 
| +      LangOptions lang_options;
 | 
| +      loc = Lexer::getLocForEndOfToken(
 | 
| +          manager.getSpellingLoc(range.getEnd()), 0,
 | 
| +          manager, lang_options);
 | 
| +      // The original code used the ending source loc of TypeSourceInfo's
 | 
| +      // TypeLoc. Unfortunately, this breaks down in the presence of attributes.
 | 
| +      // Attributes often appear at the end of a TypeLoc, e.g.
 | 
| +      //   virtual ULONG __stdcall AddRef()
 | 
| +      // has a TypeSourceInfo that looks something like:
 | 
| +      //   ULONG AddRef() __attribute(stdcall)
 | 
| +      // so a fix-it insertion would be generated to insert 'override' after
 | 
| +      // __stdcall in the code as written.
 | 
| +      // While using the spelling loc of the CXXMethodDecl fixes attribute
 | 
| +      // handling, it breaks handling of "= 0" and similar constructs.. To work
 | 
| +      // around this, scan backwards in the source text for a '=' or ')' token
 | 
| +      // and adjust the location as needed...
 | 
| +      for (SourceLocation l = loc.getLocWithOffset(-1);
 | 
| +           l != manager.getLocForStartOfFile(manager.getFileID(loc));
 | 
| +           l = l.getLocWithOffset(-1)) {
 | 
| +        l = Lexer::GetBeginningOfToken(l, manager, lang_options);
 | 
| +        Token token;
 | 
| +        // getRawToken() returns *true* on failure. In that case, just give up
 | 
| +        // and don't bother generating a possibly incorrect fix-it.
 | 
| +        if (Lexer::getRawToken(l, token, manager, lang_options, true)) {
 | 
| +          loc = SourceLocation();
 | 
| +          break;
 | 
| +        }
 | 
| +        if (token.is(tok::r_paren)) {
 | 
| +          break;
 | 
| +        } else if (token.is(tok::equal)) {
 | 
| +          loc = l;
 | 
| +          break;
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +    if (loc.isValid()) {
 | 
| +      diagnostic().Report(loc, diag_method_requires_override_)
 | 
| +          << FixItHint::CreateInsertion(loc, " override");
 | 
|      } else {
 | 
| -      diagnostic().Report(loc, diag_method_requires_override_);
 | 
| +      diagnostic().Report(range.getBegin(), diag_method_requires_override_);
 | 
|      }
 | 
|    }
 | 
|  
 | 
| @@ -559,8 +596,14 @@ FindBadConstructsConsumer::CheckRecordForRefcountIssue(
 | 
|  // Adds either a warning or error, based on the current handling of
 | 
|  // -Werror.
 | 
|  DiagnosticsEngine::Level FindBadConstructsConsumer::getErrorLevel() {
 | 
| +#if defined(LLVM_ON_WIN32)
 | 
| +  // TODO(dcheng): Re-enable -Werror for these diagnostics on Windows once all
 | 
| +  // the pre-existing warnings are cleaned up. https://crbug.com/467287
 | 
| +  return DiagnosticsEngine::Warning;
 | 
| +#else
 | 
|    return diagnostic().getWarningsAsErrors() ? DiagnosticsEngine::Error
 | 
|                                              : DiagnosticsEngine::Warning;
 | 
| +#endif
 | 
|  }
 | 
|  
 | 
|  // Returns true if |base| specifies one of the Chromium reference counted
 | 
| 
 |