diff options
author | Jordan Rupprecht <rupprecht@google.com> | 2019-05-14 21:58:59 +0000 |
---|---|---|
committer | Jordan Rupprecht <rupprecht@google.com> | 2019-05-14 21:58:59 +0000 |
commit | 46054fed6aeeabea27b9ba4a3ef81ab5ff9b9645 (patch) | |
tree | d12279f80b5729d0324f066002c838baa736fbd2 /clang-tidy/ClangTidy.cpp | |
parent | 5026a9a16d10a2edf09be54c7225f49b5789c69e (diff) | |
parent | 0eb1ac6d1df856f065717226ef34d00679a211fe (diff) |
Creating branches/google/stable and tags/google/stable/2019-05-14 from r360103upstream/stable
git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/branches/google/stable@360714 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'clang-tidy/ClangTidy.cpp')
-rw-r--r-- | clang-tidy/ClangTidy.cpp | 210 |
1 files changed, 89 insertions, 121 deletions
diff --git a/clang-tidy/ClangTidy.cpp b/clang-tidy/ClangTidy.cpp index 0feda605..1d813d65 100644 --- a/clang-tidy/ClangTidy.cpp +++ b/clang-tidy/ClangTidy.cpp @@ -1,9 +1,8 @@ //===--- tools/extra/clang-tidy/ClangTidy.cpp - Clang tidy tool -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// @@ -19,6 +18,7 @@ #include "ClangTidyDiagnosticConsumer.h" #include "ClangTidyModuleRegistry.h" #include "ClangTidyProfiling.h" +#include "ExpandModularHeadersPPCallbacks.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -35,6 +35,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Rewrite/Frontend/FixItRewriter.h" #include "clang/Rewrite/Frontend/FrontendActions.h" +#include "clang/Tooling/Core/Diagnostic.h" #if CLANG_ENABLE_STATIC_ANALYZER #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" @@ -125,61 +126,51 @@ public: } auto Diag = Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0 [%1]")) << Message.Message << Name; - for (const auto &FileAndReplacements : Error.Fix) { - for (const auto &Repl : FileAndReplacements.second) { - SourceLocation FixLoc; - ++TotalFixes; - bool CanBeApplied = false; - if (Repl.isApplicable()) { + // FIXME: explore options to support interactive fix selection. + const llvm::StringMap<Replacements> *ChosenFix = selectFirstFix(Error); + if (ApplyFixes && ChosenFix) { + for (const auto &FileAndReplacements : *ChosenFix) { + for (const auto &Repl : FileAndReplacements.second) { + ++TotalFixes; + bool CanBeApplied = false; + if (!Repl.isApplicable()) + continue; + SourceLocation FixLoc; SmallString<128> FixAbsoluteFilePath = Repl.getFilePath(); Files.makeAbsolutePath(FixAbsoluteFilePath); - if (ApplyFixes) { - tooling::Replacement R(FixAbsoluteFilePath, Repl.getOffset(), - Repl.getLength(), - Repl.getReplacementText()); - Replacements &Replacements = FileReplacements[R.getFilePath()]; - llvm::Error Err = Replacements.add(R); - if (Err) { - // FIXME: Implement better conflict handling. - llvm::errs() << "Trying to resolve conflict: " - << llvm::toString(std::move(Err)) << "\n"; - unsigned NewOffset = - Replacements.getShiftedCodePosition(R.getOffset()); - unsigned NewLength = Replacements.getShiftedCodePosition( - R.getOffset() + R.getLength()) - - NewOffset; - if (NewLength == R.getLength()) { - R = Replacement(R.getFilePath(), NewOffset, NewLength, - R.getReplacementText()); - Replacements = Replacements.merge(tooling::Replacements(R)); - CanBeApplied = true; - ++AppliedFixes; - } else { - llvm::errs() - << "Can't resolve conflict, skipping the replacement.\n"; - } - - } else { + tooling::Replacement R(FixAbsoluteFilePath, Repl.getOffset(), + Repl.getLength(), Repl.getReplacementText()); + Replacements &Replacements = FileReplacements[R.getFilePath()]; + llvm::Error Err = Replacements.add(R); + if (Err) { + // FIXME: Implement better conflict handling. + llvm::errs() << "Trying to resolve conflict: " + << llvm::toString(std::move(Err)) << "\n"; + unsigned NewOffset = + Replacements.getShiftedCodePosition(R.getOffset()); + unsigned NewLength = Replacements.getShiftedCodePosition( + R.getOffset() + R.getLength()) - + NewOffset; + if (NewLength == R.getLength()) { + R = Replacement(R.getFilePath(), NewOffset, NewLength, + R.getReplacementText()); + Replacements = Replacements.merge(tooling::Replacements(R)); CanBeApplied = true; ++AppliedFixes; + } else { + llvm::errs() + << "Can't resolve conflict, skipping the replacement.\n"; } + } else { + CanBeApplied = true; + ++AppliedFixes; } FixLoc = getLocation(FixAbsoluteFilePath, Repl.getOffset()); - SourceLocation FixEndLoc = - FixLoc.getLocWithOffset(Repl.getLength()); - // Retrieve the source range for applicable fixes. Macro definitions - // on the command line have locations in a virtual buffer and don't - // have valid file paths and are therefore not applicable. - CharSourceRange Range = - CharSourceRange::getCharRange(SourceRange(FixLoc, FixEndLoc)); - Diag << FixItHint::CreateReplacement(Range, - Repl.getReplacementText()); - } - - if (ApplyFixes) FixLocations.push_back(std::make_pair(FixLoc, CanBeApplied)); + } } } + reportFix(Diag, Error.Message.Fix); } for (auto Fix : FixLocations) { Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied @@ -250,10 +241,33 @@ private: return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset); } + void reportFix(const DiagnosticBuilder &Diag, + const llvm::StringMap<Replacements> &Fix) { + for (const auto &FileAndReplacements : Fix) { + for (const auto &Repl : FileAndReplacements.second) { + if (!Repl.isApplicable()) + continue; + SmallString<128> FixAbsoluteFilePath = Repl.getFilePath(); + Files.makeAbsolutePath(FixAbsoluteFilePath); + SourceLocation FixLoc = + getLocation(FixAbsoluteFilePath, Repl.getOffset()); + SourceLocation FixEndLoc = FixLoc.getLocWithOffset(Repl.getLength()); + // Retrieve the source range for applicable fixes. Macro definitions + // on the command line have locations in a virtual buffer and don't + // have valid file paths and are therefore not applicable. + CharSourceRange Range = + CharSourceRange::getCharRange(SourceRange(FixLoc, FixEndLoc)); + Diag << FixItHint::CreateReplacement(Range, Repl.getReplacementText()); + } + } + } + void reportNote(const tooling::DiagnosticMessage &Message) { SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset); - Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0")) + auto Diag = + Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0")) << Message.Message; + reportFix(Diag, Message.Fix); } FileManager Files; @@ -291,8 +305,10 @@ private: } // namespace ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory( - ClangTidyContext &Context) - : Context(Context), CheckFactories(new ClangTidyCheckFactories) { + ClangTidyContext &Context, + IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS) + : Context(Context), OverlayFS(OverlayFS), + CheckFactories(new ClangTidyCheckFactories) { for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(), E = ClangTidyModuleRegistry::end(); I != E; ++I) { @@ -352,14 +368,15 @@ ClangTidyASTConsumerFactory::CreateASTConsumer( clang::CompilerInstance &Compiler, StringRef File) { // FIXME: Move this to a separate method, so that CreateASTConsumer doesn't // modify Compiler. - Context.setSourceManager(&Compiler.getSourceManager()); + SourceManager *SM = &Compiler.getSourceManager(); + Context.setSourceManager(SM); Context.setCurrentFile(File); Context.setASTContext(&Compiler.getASTContext()); auto WorkingDir = Compiler.getSourceManager() .getFileManager() .getVirtualFileSystem() - ->getCurrentWorkingDirectory(); + .getCurrentWorkingDirectory(); if (WorkingDir) Context.setCurrentBuildDirectory(WorkingDir.get()); @@ -378,9 +395,19 @@ ClangTidyASTConsumerFactory::CreateASTConsumer( std::unique_ptr<ast_matchers::MatchFinder> Finder( new ast_matchers::MatchFinder(std::move(FinderOptions))); + Preprocessor *PP = &Compiler.getPreprocessor(); + Preprocessor *ModuleExpanderPP = PP; + + if (Context.getLangOpts().Modules && OverlayFS != nullptr) { + auto ModuleExpander = llvm::make_unique<ExpandModularHeadersPPCallbacks>( + &Compiler, OverlayFS); + ModuleExpanderPP = ModuleExpander->getPreprocessor(); + PP->addPPCallbacks(std::move(ModuleExpander)); + } + for (auto &Check : Checks) { Check->registerMatchers(&*Finder); - Check->registerPPCallbacks(Compiler); + Check->registerPPCallbacks(*SM, PP, ModuleExpanderPP); } std::vector<std::unique_ptr<ASTConsumer>> Consumers; @@ -435,51 +462,6 @@ ClangTidyOptions::OptionMap ClangTidyASTConsumerFactory::getCheckOptions() { return Options; } -DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message, - DiagnosticIDs::Level Level) { - return Context->diag(CheckName, Loc, Message, Level); -} - -void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) { - // For historical reasons, checks don't implement the MatchFinder run() - // callback directly. We keep the run()/check() distinction to avoid interface - // churn, and to allow us to add cross-cutting logic in the future. - check(Result); -} - -OptionsView::OptionsView(StringRef CheckName, - const ClangTidyOptions::OptionMap &CheckOptions) - : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {} - -std::string OptionsView::get(StringRef LocalName, StringRef Default) const { - const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str()); - if (Iter != CheckOptions.end()) - return Iter->second; - return Default; -} - -std::string OptionsView::getLocalOrGlobal(StringRef LocalName, - StringRef Default) const { - auto Iter = CheckOptions.find(NamePrefix + LocalName.str()); - if (Iter != CheckOptions.end()) - return Iter->second; - // Fallback to global setting, if present. - Iter = CheckOptions.find(LocalName.str()); - if (Iter != CheckOptions.end()) - return Iter->second; - return Default; -} - -void OptionsView::store(ClangTidyOptions::OptionMap &Options, - StringRef LocalName, StringRef Value) const { - Options[NamePrefix + LocalName.str()] = Value; -} - -void OptionsView::store(ClangTidyOptions::OptionMap &Options, - StringRef LocalName, int64_t Value) const { - store(Options, LocalName, llvm::itostr(Value)); -} - std::vector<std::string> getCheckNames(const ClangTidyOptions &Options, bool AllowEnablingAnalyzerAlphaCheckers) { @@ -506,7 +488,7 @@ std::vector<ClangTidyError> runClangTidy(clang::tidy::ClangTidyContext &Context, const CompilationDatabase &Compilations, ArrayRef<std::string> InputFiles, - llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS, + llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS, bool EnableCheckProfile, llvm::StringRef StoreCheckProfile) { ClangTool Tool(Compilations, InputFiles, std::make_shared<PCHContainerOperations>(), BaseFS); @@ -529,24 +511,8 @@ runClangTidy(clang::tidy::ClangTidyContext &Context, return AdjustedArgs; }; - // Remove plugins arguments. - ArgumentsAdjuster PluginArgumentsRemover = - [](const CommandLineArguments &Args, StringRef Filename) { - CommandLineArguments AdjustedArgs; - for (size_t I = 0, E = Args.size(); I < E; ++I) { - if (I + 4 < Args.size() && Args[I] == "-Xclang" && - (Args[I + 1] == "-load" || Args[I + 1] == "-add-plugin" || - StringRef(Args[I + 1]).startswith("-plugin-arg-")) && - Args[I + 2] == "-Xclang") { - I += 3; - } else - AdjustedArgs.push_back(Args[I]); - } - return AdjustedArgs; - }; - Tool.appendArgumentsAdjuster(PerFileExtraArgumentsInserter); - Tool.appendArgumentsAdjuster(PluginArgumentsRemover); + Tool.appendArgumentsAdjuster(getStripPluginsAdjuster()); Context.setEnableProfiling(EnableCheckProfile); Context.setProfileStoragePrefix(StoreCheckProfile); @@ -558,7 +524,9 @@ runClangTidy(clang::tidy::ClangTidyContext &Context, class ActionFactory : public FrontendActionFactory { public: - ActionFactory(ClangTidyContext &Context) : ConsumerFactory(Context) {} + ActionFactory(ClangTidyContext &Context, + IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS) + : ConsumerFactory(Context, BaseFS) {} FrontendAction *create() override { return new Action(&ConsumerFactory); } bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, @@ -589,7 +557,7 @@ runClangTidy(clang::tidy::ClangTidyContext &Context, ClangTidyASTConsumerFactory ConsumerFactory; }; - ActionFactory Factory(Context); + ActionFactory Factory(Context, BaseFS); Tool.run(&Factory); return DiagConsumer.take(); } @@ -600,7 +568,7 @@ void handleErrors(llvm::ArrayRef<ClangTidyError> Errors, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) { ErrorReporter Reporter(Context, Fix, BaseFS); llvm::vfs::FileSystem &FileSystem = - *Reporter.getSourceManager().getFileManager().getVirtualFileSystem(); + Reporter.getSourceManager().getFileManager().getVirtualFileSystem(); auto InitialWorkingDir = FileSystem.getCurrentWorkingDirectory(); if (!InitialWorkingDir) llvm::report_fatal_error("Cannot get current working path."); |