aboutsummaryrefslogtreecommitdiff
path: root/lib/Tooling
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Tooling')
-rw-r--r--lib/Tooling/ASTDiff/ASTDiff.cpp11
-rw-r--r--lib/Tooling/AllTUsExecution.cpp28
-rw-r--r--lib/Tooling/ArgumentsAdjusters.cpp29
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp9
-rw-r--r--lib/Tooling/CompilationDatabase.cpp7
-rw-r--r--lib/Tooling/Core/Diagnostic.cpp22
-rw-r--r--lib/Tooling/Core/Lookup.cpp92
-rw-r--r--lib/Tooling/Core/Replacement.cpp18
-rw-r--r--lib/Tooling/Execution.cpp7
-rw-r--r--lib/Tooling/FileMatchTrie.cpp7
-rw-r--r--lib/Tooling/FixIt.cpp14
-rw-r--r--lib/Tooling/Inclusions/HeaderIncludes.cpp69
-rw-r--r--lib/Tooling/Inclusions/IncludeStyle.cpp7
-rw-r--r--lib/Tooling/InterpolatingCompilationDatabase.cpp8
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp8
-rw-r--r--lib/Tooling/Refactoring.cpp7
-rw-r--r--lib/Tooling/Refactoring/ASTSelection.cpp7
-rw-r--r--lib/Tooling/Refactoring/ASTSelectionRequirements.cpp7
-rw-r--r--lib/Tooling/Refactoring/AtomicChange.cpp7
-rw-r--r--lib/Tooling/Refactoring/CMakeLists.txt3
-rw-r--r--lib/Tooling/Refactoring/Extract/Extract.cpp7
-rw-r--r--lib/Tooling/Refactoring/Extract/SourceExtraction.cpp7
-rw-r--r--lib/Tooling/Refactoring/Extract/SourceExtraction.h7
-rw-r--r--lib/Tooling/Refactoring/RefactoringActions.cpp7
-rw-r--r--lib/Tooling/Refactoring/Rename/RenamingAction.cpp7
-rw-r--r--lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp7
-rw-r--r--lib/Tooling/Refactoring/Rename/USRFinder.cpp7
-rw-r--r--lib/Tooling/Refactoring/Rename/USRFindingAction.cpp7
-rw-r--r--lib/Tooling/Refactoring/Rename/USRLocFinder.cpp11
-rw-r--r--lib/Tooling/Refactoring/SourceCode.cpp31
-rw-r--r--lib/Tooling/Refactoring/Stencil.cpp200
-rw-r--r--lib/Tooling/Refactoring/Transformer.cpp224
-rw-r--r--lib/Tooling/RefactoringCallbacks.cpp7
-rw-r--r--lib/Tooling/StandaloneExecution.cpp7
-rw-r--r--lib/Tooling/Tooling.cpp9
35 files changed, 710 insertions, 202 deletions
diff --git a/lib/Tooling/ASTDiff/ASTDiff.cpp b/lib/Tooling/ASTDiff/ASTDiff.cpp
index 592e8572c7..69eff20bff 100644
--- a/lib/Tooling/ASTDiff/ASTDiff.cpp
+++ b/lib/Tooling/ASTDiff/ASTDiff.cpp
@@ -1,9 +1,8 @@
//===- ASTDiff.cpp - AST differencing implementation-----------*- C++ -*- -===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
@@ -238,8 +237,8 @@ struct PreorderVisitor : public RecursiveASTVisitor<PreorderVisitor> {
return true;
}
bool TraverseStmt(Stmt *S) {
- if (S)
- S = S->IgnoreImplicit();
+ if (auto *E = dyn_cast_or_null<Expr>(S))
+ S = E->IgnoreImplicit();
if (isNodeExcluded(Tree.AST.getSourceManager(), S))
return true;
auto SavedState = PreTraverse(S);
diff --git a/lib/Tooling/AllTUsExecution.cpp b/lib/Tooling/AllTUsExecution.cpp
index 0f172b7829..ca9db7a561 100644
--- a/lib/Tooling/AllTUsExecution.cpp
+++ b/lib/Tooling/AllTUsExecution.cpp
@@ -1,15 +1,15 @@
//===- lib/Tooling/AllTUsExecution.cpp - Execute actions on all TUs. ------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/AllTUsExecution.h"
#include "clang/Tooling/ToolExecutorPluginRegistry.h"
#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/VirtualFileSystem.h"
namespace clang {
namespace tooling {
@@ -115,25 +115,22 @@ llvm::Error AllTUsToolExecutor::execute(
{
llvm::ThreadPool Pool(ThreadCount == 0 ? llvm::hardware_concurrency()
: ThreadCount);
- llvm::SmallString<128> InitialWorkingDir;
- if (auto EC = llvm::sys::fs::current_path(InitialWorkingDir)) {
- InitialWorkingDir = "";
- llvm::errs() << "Error while getting current working directory: "
- << EC.message() << "\n";
- }
for (std::string File : Files) {
Pool.async(
[&](std::string Path) {
Log("[" + std::to_string(Count()) + "/" + TotalNumStr +
"] Processing file " + Path);
- ClangTool Tool(Compilations, {Path});
+ // Each thread gets an indepent copy of a VFS to allow different
+ // concurrent working directories.
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
+ llvm::vfs::createPhysicalFileSystem().release();
+ ClangTool Tool(Compilations, {Path},
+ std::make_shared<PCHContainerOperations>(), FS);
Tool.appendArgumentsAdjuster(Action.second);
Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters());
for (const auto &FileAndContent : OverlayFiles)
Tool.mapVirtualFile(FileAndContent.first(),
FileAndContent.second);
- // Do not restore working dir from multiple threads to avoid races.
- Tool.setRestoreWorkingDir(false);
if (Tool.run(Action.first.get()))
AppendError(llvm::Twine("Failed to run action on ") + Path +
"\n");
@@ -142,11 +139,6 @@ llvm::Error AllTUsToolExecutor::execute(
}
// Make sure all tasks have finished before resetting the working directory.
Pool.wait();
- if (!InitialWorkingDir.empty()) {
- if (auto EC = llvm::sys::fs::set_current_path(InitialWorkingDir))
- llvm::errs() << "Error while restoring working directory: "
- << EC.message() << "\n";
- }
}
if (!ErrorMsg.empty())
diff --git a/lib/Tooling/ArgumentsAdjusters.cpp b/lib/Tooling/ArgumentsAdjusters.cpp
index c8e9c16742..002c587d6b 100644
--- a/lib/Tooling/ArgumentsAdjusters.cpp
+++ b/lib/Tooling/ArgumentsAdjusters.cpp
@@ -1,9 +1,8 @@
//===- ArgumentsAdjusters.cpp - Command line arguments adjuster -----------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
@@ -108,5 +107,27 @@ ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
};
}
+ArgumentsAdjuster getStripPluginsAdjuster() {
+ return [](const CommandLineArguments &Args, StringRef /*unused*/) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t I = 0, E = Args.size(); I != E; I++) {
+ // According to https://clang.llvm.org/docs/ClangPlugins.html
+ // plugin arguments are in the form:
+ // -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin}
+ // -Xclang <arbitrary-argument>
+ if (I + 4 < E && Args[I] == "-Xclang" &&
+ (Args[I + 1] == "-load" || Args[I + 1] == "-plugin" ||
+ llvm::StringRef(Args[I + 1]).startswith("-plugin-arg-") ||
+ Args[I + 1] == "-add-plugin") &&
+ Args[I + 2] == "-Xclang") {
+ I += 3;
+ continue;
+ }
+ AdjustedArgs.push_back(Args[I]);
+ }
+ return AdjustedArgs;
+ };
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp
index 74ad4e83ee..5faa1d7bdb 100644
--- a/lib/Tooling/CommonOptionsParser.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -1,9 +1,8 @@
//===--- CommonOptionsParser.cpp - common options for clang tools ---------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
@@ -84,8 +83,6 @@ std::vector<CompileCommand> ArgumentsAdjustingCompilations::adjustCommands(
llvm::Error CommonOptionsParser::init(
int &argc, const char **argv, cl::OptionCategory &Category,
llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
- static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden,
- cl::sub(*cl::AllSubCommands));
static cl::opt<std::string> BuildPath("p", cl::desc("Build path"),
cl::Optional, cl::cat(Category),
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index cce8e1f1df..4c64750bef 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -1,9 +1,8 @@
//===- CompilationDatabase.cpp --------------------------------------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Tooling/Core/Diagnostic.cpp b/lib/Tooling/Core/Diagnostic.cpp
index e3a33d9a37..235bd7fc14 100644
--- a/lib/Tooling/Core/Diagnostic.cpp
+++ b/lib/Tooling/Core/Diagnostic.cpp
@@ -1,9 +1,8 @@
//===--- Diagnostic.cpp - Framework for clang diagnostics tools ----------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
@@ -13,6 +12,7 @@
#include "clang/Tooling/Core/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/STLExtras.h"
namespace clang {
namespace tooling {
@@ -41,11 +41,21 @@ Diagnostic::Diagnostic(llvm::StringRef DiagnosticName,
Diagnostic::Diagnostic(llvm::StringRef DiagnosticName,
const DiagnosticMessage &Message,
- const llvm::StringMap<Replacements> &Fix,
const SmallVector<DiagnosticMessage, 1> &Notes,
Level DiagLevel, llvm::StringRef BuildDirectory)
- : DiagnosticName(DiagnosticName), Message(Message), Fix(Fix), Notes(Notes),
+ : DiagnosticName(DiagnosticName), Message(Message), Notes(Notes),
DiagLevel(DiagLevel), BuildDirectory(BuildDirectory) {}
+const llvm::StringMap<Replacements> *selectFirstFix(const Diagnostic& D) {
+ if (!D.Message.Fix.empty())
+ return &D.Message.Fix;
+ auto Iter = llvm::find_if(D.Notes, [](const tooling::DiagnosticMessage &D) {
+ return !D.Fix.empty();
+ });
+ if (Iter != D.Notes.end())
+ return &Iter->Fix;
+ return nullptr;
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/lib/Tooling/Core/Lookup.cpp b/lib/Tooling/Core/Lookup.cpp
index cc448d144e..735a5df5ed 100644
--- a/lib/Tooling/Core/Lookup.cpp
+++ b/lib/Tooling/Core/Lookup.cpp
@@ -1,9 +1,8 @@
//===--- Lookup.cpp - Framework for clang refactoring tools ---------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
@@ -15,6 +14,8 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclarationName.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/SmallVector.h"
using namespace clang;
using namespace clang::tooling;
@@ -115,38 +116,72 @@ static bool isFullyQualified(const NestedNameSpecifier *NNS) {
return false;
}
-// Returns true if spelling symbol \p QName as \p Spelling in \p UseContext is
-// ambiguous. For example, if QName is "::y::bar" and the spelling is "y::bar"
-// in `UseContext` "a" that contains a nested namespace "a::y", then "y::bar"
-// can be resolved to ::a::y::bar, which can cause compile error.
+// Adds more scope specifier to the spelled name until the spelling is not
+// ambiguous. A spelling is ambiguous if the resolution of the symbol is
+// ambiguous. For example, if QName is "::y::bar", the spelling is "y::bar", and
+// context contains a nested namespace "a::y", then "y::bar" can be resolved to
+// ::a::y::bar in the context, which can cause compile error.
// FIXME: consider using namespaces.
-static bool isAmbiguousNameInScope(StringRef Spelling, StringRef QName,
- const DeclContext &UseContext) {
+static std::string disambiguateSpellingInScope(StringRef Spelling,
+ StringRef QName,
+ const DeclContext &UseContext,
+ SourceLocation UseLoc) {
assert(QName.startswith("::"));
+ assert(QName.endswith(Spelling));
if (Spelling.startswith("::"))
- return false;
+ return Spelling;
- // Lookup the first component of Spelling in all enclosing namespaces and
- // check if there is any existing symbols with the same name but in different
- // scope.
- StringRef Head = Spelling.split("::").first;
+ auto UnspelledSpecifier = QName.drop_back(Spelling.size());
+ llvm::SmallVector<llvm::StringRef, 2> UnspelledScopes;
+ UnspelledSpecifier.split(UnspelledScopes, "::", /*MaxSplit=*/-1,
+ /*KeepEmpty=*/false);
- llvm::SmallVector<const NamespaceDecl *, 4> UseNamespaces =
+ llvm::SmallVector<const NamespaceDecl *, 4> EnclosingNamespaces =
getAllNamedNamespaces(&UseContext);
auto &AST = UseContext.getParentASTContext();
StringRef TrimmedQName = QName.substr(2);
- for (const auto *NS : UseNamespaces) {
- auto LookupRes = NS->lookup(DeclarationName(&AST.Idents.get(Head)));
- if (!LookupRes.empty()) {
- for (const NamedDecl *Res : LookupRes)
- if (!TrimmedQName.startswith(Res->getQualifiedNameAsString()))
- return true;
+ const auto &SM = UseContext.getParentASTContext().getSourceManager();
+ UseLoc = SM.getSpellingLoc(UseLoc);
+
+ auto IsAmbiguousSpelling = [&](const llvm::StringRef CurSpelling) {
+ if (CurSpelling.startswith("::"))
+ return false;
+ // Lookup the first component of Spelling in all enclosing namespaces
+ // and check if there is any existing symbols with the same name but in
+ // different scope.
+ StringRef Head = CurSpelling.split("::").first;
+ for (const auto *NS : EnclosingNamespaces) {
+ auto LookupRes = NS->lookup(DeclarationName(&AST.Idents.get(Head)));
+ if (!LookupRes.empty()) {
+ for (const NamedDecl *Res : LookupRes)
+ // If `Res` is not visible in `UseLoc`, we don't consider it
+ // ambiguous. For example, a reference in a header file should not be
+ // affected by a potentially ambiguous name in some file that includes
+ // the header.
+ if (!TrimmedQName.startswith(Res->getQualifiedNameAsString()) &&
+ SM.isBeforeInTranslationUnit(
+ SM.getSpellingLoc(Res->getLocation()), UseLoc))
+ return true;
+ }
+ }
+ return false;
+ };
+
+ // Add more qualifiers until the spelling is not ambiguous.
+ std::string Disambiguated = Spelling;
+ while (IsAmbiguousSpelling(Disambiguated)) {
+ if (UnspelledScopes.empty()) {
+ Disambiguated = "::" + Disambiguated;
+ } else {
+ Disambiguated = (UnspelledScopes.back() + "::" + Disambiguated).str();
+ UnspelledScopes.pop_back();
}
}
- return false;
+ return Disambiguated;
}
std::string tooling::replaceNestedName(const NestedNameSpecifier *Use,
+ SourceLocation UseLoc,
const DeclContext *UseContext,
const NamedDecl *FromDecl,
StringRef ReplacementString) {
@@ -180,12 +215,7 @@ std::string tooling::replaceNestedName(const NestedNameSpecifier *Use,
// specific).
StringRef Suggested = getBestNamespaceSubstr(UseContext, ReplacementString,
isFullyQualified(Use));
- // Use the fully qualified name if the suggested name is ambiguous.
- // FIXME: consider re-shortening the name until the name is not ambiguous. We
- // are not doing this because ambiguity is pretty bad and we should not try to
- // be clever in handling such cases. Making this noticeable to users seems to
- // be a better option.
- return isAmbiguousNameInScope(Suggested, ReplacementString, *UseContext)
- ? ReplacementString
- : Suggested;
+
+ return disambiguateSpellingInScope(Suggested, ReplacementString, *UseContext,
+ UseLoc);
}
diff --git a/lib/Tooling/Core/Replacement.cpp b/lib/Tooling/Core/Replacement.cpp
index 3b7e39814a..546158714e 100644
--- a/lib/Tooling/Core/Replacement.cpp
+++ b/lib/Tooling/Core/Replacement.cpp
@@ -1,9 +1,8 @@
//===- Replacement.cpp - Framework for clang refactoring tools ------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
@@ -520,12 +519,11 @@ calculateRangesAfterReplacements(const Replacements &Replaces,
return MergedRanges;
tooling::Replacements FakeReplaces;
for (const auto &R : MergedRanges) {
- auto Err = FakeReplaces.add(Replacement(Replaces.begin()->getFilePath(),
- R.getOffset(), R.getLength(),
- std::string(R.getLength(), ' ')));
- assert(!Err &&
- "Replacements must not conflict since ranges have been merged.");
- llvm::consumeError(std::move(Err));
+ llvm::cantFail(
+ FakeReplaces.add(Replacement(Replaces.begin()->getFilePath(),
+ R.getOffset(), R.getLength(),
+ std::string(R.getLength(), ' '))),
+ "Replacements must not conflict since ranges have been merged.");
}
return FakeReplaces.merge(Replaces).getAffectedRanges();
}
diff --git a/lib/Tooling/Execution.cpp b/lib/Tooling/Execution.cpp
index 9ddb18a57b..c39a4fcdac 100644
--- a/lib/Tooling/Execution.cpp
+++ b/lib/Tooling/Execution.cpp
@@ -1,9 +1,8 @@
//===- lib/Tooling/Execution.cpp - Implements tool execution framework. ---===//
//
-// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Tooling/FileMatchTrie.cpp b/lib/Tooling/FileMatchTrie.cpp
index 202b3f00f3..7df5a16fd8 100644
--- a/lib/Tooling/FileMatchTrie.cpp
+++ b/lib/Tooling/FileMatchTrie.cpp
@@ -1,9 +1,8 @@
//===- FileMatchTrie.cpp --------------------------------------------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Tooling/FixIt.cpp b/lib/Tooling/FixIt.cpp
index 70942c5ac8..76c92c5437 100644
--- a/lib/Tooling/FixIt.cpp
+++ b/lib/Tooling/FixIt.cpp
@@ -1,9 +1,8 @@
//===--- FixIt.cpp - FixIt Hint utilities -----------------------*- C++ -*-===//
//
-// 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,12 +18,11 @@ namespace tooling {
namespace fixit {
namespace internal {
-StringRef getText(SourceRange Range, const ASTContext &Context) {
- return Lexer::getSourceText(CharSourceRange::getTokenRange(Range),
- Context.getSourceManager(),
+StringRef getText(CharSourceRange Range, const ASTContext &Context) {
+ return Lexer::getSourceText(Range, Context.getSourceManager(),
Context.getLangOpts());
}
-} // end namespace internal
+} // namespace internal
} // end namespace fixit
} // end namespace tooling
diff --git a/lib/Tooling/Inclusions/HeaderIncludes.cpp b/lib/Tooling/Inclusions/HeaderIncludes.cpp
index c74ad0b9cd..a7f79c33bc 100644
--- a/lib/Tooling/Inclusions/HeaderIncludes.cpp
+++ b/lib/Tooling/Inclusions/HeaderIncludes.cpp
@@ -1,15 +1,15 @@
//===--- HeaderIncludes.cpp - Insert/Delete #includes --*- C++ -*----------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Inclusions/HeaderIncludes.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/FormatVariadic.h"
namespace clang {
@@ -51,12 +51,16 @@ unsigned getOffsetAfterTokenSequence(
// Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is,
// \p Tok will be the token after this directive; otherwise, it can be any token
-// after the given \p Tok (including \p Tok).
-bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef Name, Token &Tok) {
+// after the given \p Tok (including \p Tok). If \p RawIDName is provided, the
+// (second) raw_identifier name is checked.
+bool checkAndConsumeDirectiveWithName(
+ Lexer &Lex, StringRef Name, Token &Tok,
+ llvm::Optional<StringRef> RawIDName = llvm::None) {
bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
Tok.is(tok::raw_identifier) &&
Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
- Tok.is(tok::raw_identifier);
+ Tok.is(tok::raw_identifier) &&
+ (!RawIDName || Tok.getRawIdentifier() == *RawIDName);
if (Matched)
Lex.LexFromRawLexer(Tok);
return Matched;
@@ -69,24 +73,45 @@ void skipComments(Lexer &Lex, Token &Tok) {
}
// Returns the offset after header guard directives and any comments
-// before/after header guards. If no header guard presents in the code, this
-// will returns the offset after skipping all comments from the start of the
-// code.
+// before/after header guards (e.g. #ifndef/#define pair, #pragma once). If no
+// header guard is present in the code, this will return the offset after
+// skipping all comments from the start of the code.
unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
StringRef Code,
const IncludeStyle &Style) {
- return getOffsetAfterTokenSequence(
- FileName, Code, Style,
- [](const SourceManager &SM, Lexer &Lex, Token Tok) {
- skipComments(Lex, Tok);
- unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
- if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) {
- skipComments(Lex, Tok);
- if (checkAndConsumeDirectiveWithName(Lex, "define", Tok))
- return SM.getFileOffset(Tok.getLocation());
- }
- return InitialOffset;
- });
+ // \p Consume returns location after header guard or 0 if no header guard is
+ // found.
+ auto ConsumeHeaderGuardAndComment =
+ [&](std::function<unsigned(const SourceManager &SM, Lexer &Lex,
+ Token Tok)>
+ Consume) {
+ return getOffsetAfterTokenSequence(
+ FileName, Code, Style,
+ [&Consume](const SourceManager &SM, Lexer &Lex, Token Tok) {
+ skipComments(Lex, Tok);
+ unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
+ return std::max(InitialOffset, Consume(SM, Lex, Tok));
+ });
+ };
+ return std::max(
+ // #ifndef/#define
+ ConsumeHeaderGuardAndComment(
+ [](const SourceManager &SM, Lexer &Lex, Token Tok) -> unsigned {
+ if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) {
+ skipComments(Lex, Tok);
+ if (checkAndConsumeDirectiveWithName(Lex, "define", Tok))
+ return SM.getFileOffset(Tok.getLocation());
+ }
+ return 0;
+ }),
+ // #pragma once
+ ConsumeHeaderGuardAndComment(
+ [](const SourceManager &SM, Lexer &Lex, Token Tok) -> unsigned {
+ if (checkAndConsumeDirectiveWithName(Lex, "pragma", Tok,
+ StringRef("once")))
+ return SM.getFileOffset(Tok.getLocation());
+ return 0;
+ }));
}
// Check if a sequence of tokens is like
diff --git a/lib/Tooling/Inclusions/IncludeStyle.cpp b/lib/Tooling/Inclusions/IncludeStyle.cpp
index 3597710f1f..c53c82c836 100644
--- a/lib/Tooling/Inclusions/IncludeStyle.cpp
+++ b/lib/Tooling/Inclusions/IncludeStyle.cpp
@@ -1,9 +1,8 @@
//===--- IncludeStyle.cpp - Style of C++ #include directives -----*- C++-*-===//
//
-// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Tooling/InterpolatingCompilationDatabase.cpp b/lib/Tooling/InterpolatingCompilationDatabase.cpp
index 4d0d84f660..5124340892 100644
--- a/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -1,9 +1,8 @@
//===- InterpolatingCompilationDatabase.cpp ---------------------*- C++ -*-===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
@@ -227,6 +226,7 @@ struct TransferableCommand {
LangStandard::getLangStandardForKind(Std).getName()).str());
}
Result.CommandLine.push_back(Filename);
+ Result.Heuristic = "inferred from " + Cmd.Filename;
return Result;
}
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
index b0feaa229c..3414f7db58 100644
--- a/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -1,9 +1,8 @@
//===- JSONCompilationDatabase.cpp ----------------------------------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
@@ -371,6 +370,7 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
SmallString<128> AbsolutePath(
Directory->getValue(DirectoryStorage));
llvm::sys::path::append(AbsolutePath, FileName);
+ llvm::sys::path::remove_dots(AbsolutePath, /*remove_dot_dot=*/ true);
llvm::sys::path::native(AbsolutePath, NativeFilePath);
} else {
llvm::sys::path::native(FileName, NativeFilePath);
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index db34c952d7..f379a9c3bc 100644
--- a/lib/Tooling/Refactoring.cpp
+++ b/lib/Tooling/Refactoring.cpp
@@ -1,9 +1,8 @@
//===--- Refactoring.cpp - Framework for clang refactoring tools ----------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Tooling/Refactoring/ASTSelection.cpp b/lib/Tooling/Refactoring/ASTSelection.cpp
index b8f996d821..64e57af590 100644
--- a/lib/Tooling/Refactoring/ASTSelection.cpp
+++ b/lib/Tooling/Refactoring/ASTSelection.cpp
@@ -1,9 +1,8 @@
//===--- ASTSelection.cpp - Clang refactoring library ---------------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp b/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
index c0232c5da4..14fc66a979 100644
--- a/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
+++ b/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
@@ -1,9 +1,8 @@
//===--- ASTSelectionRequirements.cpp - Clang refactoring library ---------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Tooling/Refactoring/AtomicChange.cpp b/lib/Tooling/Refactoring/AtomicChange.cpp
index e8b0fdbeb6..4cf63306d2 100644
--- a/lib/Tooling/Refactoring/AtomicChange.cpp
+++ b/lib/Tooling/Refactoring/AtomicChange.cpp
@@ -1,9 +1,8 @@
//===--- AtomicChange.cpp - AtomicChange implementation -----------------*- C++ -*-===//
//
-// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Tooling/Refactoring/CMakeLists.txt b/lib/Tooling/Refactoring/CMakeLists.txt
index 402b5d3c6a..37e40e634e 100644
--- a/lib/Tooling/Refactoring/CMakeLists.txt
+++ b/lib/Tooling/Refactoring/CMakeLists.txt
@@ -12,6 +12,9 @@ add_clang_library(clangToolingRefactor
Rename/USRFinder.cpp
Rename/USRFindingAction.cpp
Rename/USRLocFinder.cpp
+ SourceCode.cpp
+ Stencil.cpp
+ Transformer.cpp
LINK_LIBS
clangAST
diff --git a/lib/Tooling/Refactoring/Extract/Extract.cpp b/lib/Tooling/Refactoring/Extract/Extract.cpp
index 7a741bdb2e..f5b94a4621 100644
--- a/lib/Tooling/Refactoring/Extract/Extract.cpp
+++ b/lib/Tooling/Refactoring/Extract/Extract.cpp
@@ -1,9 +1,8 @@
//===--- Extract.cpp - Clang refactoring library --------------------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
///
diff --git a/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp b/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
index 7fd8cc2d3c..533c373e35 100644
--- a/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
+++ b/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
@@ -1,9 +1,8 @@
//===--- SourceExtraction.cpp - Clang refactoring library -----------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Tooling/Refactoring/Extract/SourceExtraction.h b/lib/Tooling/Refactoring/Extract/SourceExtraction.h
index 4b4bd8b477..545eb6c1a1 100644
--- a/lib/Tooling/Refactoring/Extract/SourceExtraction.h
+++ b/lib/Tooling/Refactoring/Extract/SourceExtraction.h
@@ -1,9 +1,8 @@
//===--- SourceExtraction.cpp - Clang refactoring library -----------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Tooling/Refactoring/RefactoringActions.cpp b/lib/Tooling/Refactoring/RefactoringActions.cpp
index 37a1639cb4..1a3833243a 100644
--- a/lib/Tooling/Refactoring/RefactoringActions.cpp
+++ b/lib/Tooling/Refactoring/RefactoringActions.cpp
@@ -1,9 +1,8 @@
//===--- RefactoringActions.cpp - Constructs refactoring actions ----------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Tooling/Refactoring/Rename/RenamingAction.cpp b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
index 44ffae90ef..3a9c477210 100644
--- a/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
+++ b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
@@ -1,9 +1,8 @@
//===--- RenamingAction.cpp - Clang refactoring library -------------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
///
diff --git a/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp b/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
index ea64b2c1aa..8cc1ffaf44 100644
--- a/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
+++ b/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
@@ -1,9 +1,8 @@
//===--- SymbolOccurrences.cpp - Clang refactoring library ----------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Tooling/Refactoring/Rename/USRFinder.cpp b/lib/Tooling/Refactoring/Rename/USRFinder.cpp
index 4ed805fd50..55111202ac 100644
--- a/lib/Tooling/Refactoring/Rename/USRFinder.cpp
+++ b/lib/Tooling/Refactoring/Rename/USRFinder.cpp
@@ -1,9 +1,8 @@
//===--- USRFinder.cpp - Clang refactoring library ------------------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
///
diff --git a/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp b/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
index 2e7c9b0cc3..54c6f3e734 100644
--- a/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
+++ b/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
@@ -1,9 +1,8 @@
//===--- USRFindingAction.cpp - Clang refactoring library -----------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
///
diff --git a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
index 7f60cf54c8..408e184f5b 100644
--- a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
+++ b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
@@ -1,9 +1,8 @@
//===--- USRLocFinder.cpp - Clang refactoring library ---------------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
///
@@ -543,8 +542,8 @@ createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
if (!llvm::isa<clang::TranslationUnitDecl>(
RenameInfo.Context->getDeclContext())) {
ReplacedName = tooling::replaceNestedName(
- RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
- RenameInfo.FromDecl,
+ RenameInfo.Specifier, RenameInfo.Begin,
+ RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl,
NewName.startswith("::") ? NewName.str()
: ("::" + NewName).str());
} else {
diff --git a/lib/Tooling/Refactoring/SourceCode.cpp b/lib/Tooling/Refactoring/SourceCode.cpp
new file mode 100644
index 0000000000..3a97e178bb
--- /dev/null
+++ b/lib/Tooling/Refactoring/SourceCode.cpp
@@ -0,0 +1,31 @@
+//===--- SourceCode.cpp - Source code manipulation routines -----*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides functions that simplify extraction of source code.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Tooling/Refactoring/SourceCode.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang;
+
+StringRef clang::tooling::getText(CharSourceRange Range,
+ const ASTContext &Context) {
+ return Lexer::getSourceText(Range, Context.getSourceManager(),
+ Context.getLangOpts());
+}
+
+CharSourceRange clang::tooling::maybeExtendRange(CharSourceRange Range,
+ tok::TokenKind Next,
+ ASTContext &Context) {
+ Optional<Token> Tok = Lexer::findNextToken(
+ Range.getEnd(), Context.getSourceManager(), Context.getLangOpts());
+ if (!Tok || !Tok->is(Next))
+ return Range;
+ return CharSourceRange::getTokenRange(Range.getBegin(), Tok->getLocation());
+}
diff --git a/lib/Tooling/Refactoring/Stencil.cpp b/lib/Tooling/Refactoring/Stencil.cpp
new file mode 100644
index 0000000000..8fe589b098
--- /dev/null
+++ b/lib/Tooling/Refactoring/Stencil.cpp
@@ -0,0 +1,200 @@
+//===--- Stencil.cpp - Stencil implementation -------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Stencil.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Expr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Refactoring/SourceCode.h"
+#include "llvm/Support/Errc.h"
+#include <atomic>
+#include <memory>
+#include <string>
+
+using namespace clang;
+using namespace tooling;
+
+using ast_matchers::MatchFinder;
+using llvm::Error;
+
+// A down_cast function to safely down cast a StencilPartInterface to a subclass
+// D. Returns nullptr if P is not an instance of D.
+template <typename D> const D *down_cast(const StencilPartInterface *P) {
+ if (P == nullptr || D::typeId() != P->typeId())
+ return nullptr;
+ return static_cast<const D *>(P);
+}
+
+static llvm::Expected<ast_type_traits::DynTypedNode>
+getNode(const ast_matchers::BoundNodes &Nodes, StringRef Id) {
+ auto &NodesMap = Nodes.getMap();
+ auto It = NodesMap.find(Id);
+ if (It == NodesMap.end())
+ return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
+ "Id not bound: " + Id);
+ return It->second;
+}
+
+namespace {
+// An arbitrary fragment of code within a stencil.
+struct RawTextData {
+ explicit RawTextData(std::string T) : Text(std::move(T)) {}
+ std::string Text;
+};
+
+// A debugging operation to dump the AST for a particular (bound) AST node.
+struct DebugPrintNodeOpData {
+ explicit DebugPrintNodeOpData(std::string S) : Id(std::move(S)) {}
+ std::string Id;
+};
+// Whether to associate a trailing semicolon with a node when identifying it's
+// text. This flag is needed for expressions (clang::Expr), because their role
+// is ambiguous when they are also complete statements. When this flag is
+// `Always`, an expression node will be treated like a statement, and will
+// therefore be associated with any trailing semicolon.
+enum class SemiAssociation : bool {
+ Always,
+ Inferred,
+};
+
+// A reference to a particular (bound) AST node.
+struct NodeRefData {
+ explicit NodeRefData(std::string S, SemiAssociation SA)
+ : Id(std::move(S)), SemiAssoc(SA) {}
+ std::string Id;
+ SemiAssociation SemiAssoc;
+};
+} // namespace
+
+bool isEqualData(const RawTextData &A, const RawTextData &B) {
+ return A.Text == B.Text;
+}
+
+bool isEqualData(const DebugPrintNodeOpData &A, const DebugPrintNodeOpData &B) {
+ return A.Id == B.Id;
+}
+
+bool isEqualData(const NodeRefData &A, const NodeRefData &B) {
+ return A.Id == B.Id && A.SemiAssoc == B.SemiAssoc;
+}
+
+// The `evalData()` overloads evaluate the given stencil data to a string, given
+// the match result, and append it to `Result`. We define an overload for each
+// type of stencil data.
+
+Error evalData(const RawTextData &Data, const MatchFinder::MatchResult &,
+ std::string *Result) {
+ Result->append(Data.Text);
+ return Error::success();
+}
+
+Error evalData(const DebugPrintNodeOpData &Data,
+ const MatchFinder::MatchResult &Match, std::string *Result) {
+ std::string Output;
+ llvm::raw_string_ostream Os(Output);
+ auto NodeOrErr = getNode(Match.Nodes, Data.Id);
+ if (auto Err = NodeOrErr.takeError())
+ return Err;
+ NodeOrErr->print(Os, PrintingPolicy(Match.Context->getLangOpts()));
+ *Result += Os.str();
+ return Error::success();
+}
+
+Error evalData(const NodeRefData &Data, const MatchFinder::MatchResult &Match,
+ std::string *Result) {
+ auto NodeOrErr = getNode(Match.Nodes, Data.Id);
+ if (auto Err = NodeOrErr.takeError())
+ return Err;
+ auto &Node = *NodeOrErr;
+ switch (Data.SemiAssoc) {
+ case SemiAssociation::Inferred:
+ // Include the semicolon for non-expression statements:
+ *Result += Node.get<Stmt>() != nullptr && Node.get<Expr>() == nullptr
+ ? getExtendedText(NodeOrErr.get(), tok::TokenKind::semi,
+ *Match.Context)
+ : getText(NodeOrErr.get(), *Match.Context);
+ break;
+ case SemiAssociation::Always:
+ *Result +=
+ getExtendedText(NodeOrErr.get(), tok::TokenKind::semi, *Match.Context);
+ break;
+ }
+ return Error::success();
+}
+
+template <typename T>
+class StencilPartImpl : public StencilPartInterface {
+ T Data;
+
+public:
+ template <typename... Ps>
+ explicit StencilPartImpl(Ps &&... Args)
+ : StencilPartInterface(StencilPartImpl::typeId()),
+ Data(std::forward<Ps>(Args)...) {}
+
+ // Generates a unique identifier for this class (specifically, one per
+ // instantiation of the template).
+ static const void* typeId() {
+ static bool b;
+ return &b;
+ }
+
+ Error eval(const MatchFinder::MatchResult &Match,
+ std::string *Result) const override {
+ return evalData(Data, Match, Result);
+ }
+
+ bool isEqual(const StencilPartInterface &Other) const override {
+ if (const auto *OtherPtr = down_cast<StencilPartImpl>(&Other))
+ return isEqualData(Data, OtherPtr->Data);
+ return false;
+ }
+};
+
+namespace {
+using RawText = StencilPartImpl<RawTextData>;
+using DebugPrintNodeOp = StencilPartImpl<DebugPrintNodeOpData>;
+using NodeRef = StencilPartImpl<NodeRefData>;
+} // namespace
+
+StencilPart Stencil::wrap(StringRef Text) {
+ return stencil::text(Text);
+}
+
+void Stencil::append(Stencil OtherStencil) {
+ for (auto &Part : OtherStencil.Parts)
+ Parts.push_back(std::move(Part));
+}
+
+llvm::Expected<std::string>
+Stencil::eval(const MatchFinder::MatchResult &Match) const {
+ std::string Result;
+ for (const auto &Part : Parts)
+ if (auto Err = Part.eval(Match, &Result))
+ return std::move(Err);
+ return Result;
+}
+
+StencilPart stencil::text(StringRef Text) {
+ return StencilPart(std::make_shared<RawText>(Text));
+}
+
+StencilPart stencil::node(StringRef Id) {
+ return StencilPart(std::make_shared<NodeRef>(Id, SemiAssociation::Inferred));
+}
+
+StencilPart stencil::sNode(StringRef Id) {
+ return StencilPart(std::make_shared<NodeRef>(Id, SemiAssociation::Always));
+}
+
+StencilPart stencil::dPrint(StringRef Id) {
+ return StencilPart(std::make_shared<DebugPrintNodeOp>(Id));
+}
diff --git a/lib/Tooling/Refactoring/Transformer.cpp b/lib/Tooling/Refactoring/Transformer.cpp
new file mode 100644
index 0000000000..57a836567d
--- /dev/null
+++ b/lib/Tooling/Refactoring/Transformer.cpp
@@ -0,0 +1,224 @@
+//===--- Transformer.cpp - Transformer library implementation ---*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Transformer.h"
+#include "clang/AST/Expr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/Refactoring/SourceCode.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include <deque>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace clang;
+using namespace tooling;
+
+using ast_matchers::MatchFinder;
+using ast_type_traits::ASTNodeKind;
+using ast_type_traits::DynTypedNode;
+using llvm::Error;
+using llvm::Expected;
+using llvm::Optional;
+using llvm::StringError;
+using llvm::StringRef;
+using llvm::Twine;
+
+using MatchResult = MatchFinder::MatchResult;
+
+// Did the text at this location originate in a macro definition (aka. body)?
+// For example,
+//
+// #define NESTED(x) x
+// #define MACRO(y) { int y = NESTED(3); }
+// if (true) MACRO(foo)
+//
+// The if statement expands to
+//
+// if (true) { int foo = 3; }
+// ^ ^
+// Loc1 Loc2
+//
+// For SourceManager SM, SM.isMacroArgExpansion(Loc1) and
+// SM.isMacroArgExpansion(Loc2) are both true, but isOriginMacroBody(sm, Loc1)
+// is false, because "foo" originated in the source file (as an argument to a
+// macro), whereas isOriginMacroBody(SM, Loc2) is true, because "3" originated
+// in the definition of MACRO.
+static bool isOriginMacroBody(const clang::SourceManager &SM,
+ clang::SourceLocation Loc) {
+ while (Loc.isMacroID()) {
+ if (SM.isMacroBodyExpansion(Loc))
+ return true;
+ // Otherwise, it must be in an argument, so we continue searching up the
+ // invocation stack. getImmediateMacroCallerLoc() gives the location of the
+ // argument text, inside the call text.
+ Loc = SM.getImmediateMacroCallerLoc(Loc);
+ }
+ return false;
+}
+
+static llvm::Error invalidArgumentError(Twine Message) {
+ return llvm::make_error<StringError>(llvm::errc::invalid_argument, Message);
+}
+
+static llvm::Error typeError(StringRef Id, const ASTNodeKind &Kind,
+ Twine Message) {
+ return invalidArgumentError(
+ Message + " (node id=" + Id + " kind=" + Kind.asStringRef() + ")");
+}
+
+static llvm::Error missingPropertyError(StringRef Id, Twine Description,
+ StringRef Property) {
+ return invalidArgumentError(Description + " requires property '" + Property +
+ "' (node id=" + Id + ")");
+}
+
+static Expected<CharSourceRange>
+getTargetRange(StringRef Target, const DynTypedNode &Node, ASTNodeKind Kind,
+ NodePart TargetPart, ASTContext &Context) {
+ switch (TargetPart) {
+ case NodePart::Node: {
+ // For non-expression statements, associate any trailing semicolon with the
+ // statement text. However, if the target was intended as an expression (as
+ // indicated by its kind) then we do not associate any trailing semicolon
+ // with it. We only associate the exact expression text.
+ if (Node.get<Stmt>() != nullptr) {
+ auto ExprKind = ASTNodeKind::getFromNodeKind<clang::Expr>();
+ if (!ExprKind.isBaseOf(Kind))
+ return getExtendedRange(Node, tok::TokenKind::semi, Context);
+ }
+ return CharSourceRange::getTokenRange(Node.getSourceRange());
+ }
+ case NodePart::Member:
+ if (auto *M = Node.get<clang::MemberExpr>())
+ return CharSourceRange::getTokenRange(
+ M->getMemberNameInfo().getSourceRange());
+ return typeError(Target, Node.getNodeKind(),
+ "NodePart::Member applied to non-MemberExpr");
+ case NodePart::Name:
+ if (const auto *D = Node.get<clang::NamedDecl>()) {
+ if (!D->getDeclName().isIdentifier())
+ return missingPropertyError(Target, "NodePart::Name", "identifier");
+ SourceLocation L = D->getLocation();
+ auto R = CharSourceRange::getTokenRange(L, L);
+ // Verify that the range covers exactly the name.
+ // FIXME: extend this code to support cases like `operator +` or
+ // `foo<int>` for which this range will be too short. Doing so will
+ // require subcasing `NamedDecl`, because it doesn't provide virtual
+ // access to the \c DeclarationNameInfo.
+ if (getText(R, Context) != D->getName())
+ return CharSourceRange();
+ return R;
+ }
+ if (const auto *E = Node.get<clang::DeclRefExpr>()) {
+ if (!E->getNameInfo().getName().isIdentifier())
+ return missingPropertyError(Target, "NodePart::Name", "identifier");
+ SourceLocation L = E->getLocation();
+ return CharSourceRange::getTokenRange(L, L);
+ }
+ if (const auto *I = Node.get<clang::CXXCtorInitializer>()) {
+ if (!I->isMemberInitializer() && I->isWritten())
+ return missingPropertyError(Target, "NodePart::Name",
+ "explicit member initializer");
+ SourceLocation L = I->getMemberLocation();
+ return CharSourceRange::getTokenRange(L, L);
+ }
+ return typeError(
+ Target, Node.getNodeKind(),
+ "NodePart::Name applied to neither DeclRefExpr, NamedDecl nor "
+ "CXXCtorInitializer");
+ }
+ llvm_unreachable("Unexpected case in NodePart type.");
+}
+
+Expected<SmallVector<Transformation, 1>>
+tooling::translateEdits(const MatchResult &Result,
+ llvm::ArrayRef<ASTEdit> Edits) {
+ SmallVector<Transformation, 1> Transformations;
+ auto &NodesMap = Result.Nodes.getMap();
+ for (const auto &Edit : Edits) {
+ auto It = NodesMap.find(Edit.Target);
+ assert(It != NodesMap.end() && "Edit target must be bound in the match.");
+
+ Expected<CharSourceRange> Range = getTargetRange(
+ Edit.Target, It->second, Edit.Kind, Edit.Part, *Result.Context);
+ if (!Range)
+ return Range.takeError();
+ if (Range->isInvalid() ||
+ isOriginMacroBody(*Result.SourceManager, Range->getBegin()))
+ return SmallVector<Transformation, 0>();
+ auto Replacement = Edit.Replacement(Result);
+ if (!Replacement)
+ return Replacement.takeError();
+ Transformation T;
+ T.Range = *Range;
+ T.Replacement = std::move(*Replacement);
+ Transformations.push_back(std::move(T));
+ }
+ return Transformations;
+}
+
+RewriteRule tooling::makeRule(ast_matchers::internal::DynTypedMatcher M,
+ SmallVector<ASTEdit, 1> Edits) {
+ M.setAllowBind(true);
+ // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
+ return RewriteRule{*M.tryBind(RewriteRule::RootId), std::move(Edits),
+ nullptr};
+}
+
+constexpr llvm::StringLiteral RewriteRule::RootId;
+
+void Transformer::registerMatchers(MatchFinder *MatchFinder) {
+ MatchFinder->addDynamicMatcher(Rule.Matcher, this);
+}
+
+void Transformer::run(const MatchResult &Result) {
+ if (Result.Context->getDiagnostics().hasErrorOccurred())
+ return;
+
+ // Verify the existence and validity of the AST node that roots this rule.
+ auto &NodesMap = Result.Nodes.getMap();
+ auto Root = NodesMap.find(RewriteRule::RootId);
+ assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
+ SourceLocation RootLoc = Result.SourceManager->getExpansionLoc(
+ Root->second.getSourceRange().getBegin());
+ assert(RootLoc.isValid() && "Invalid location for Root node of match.");
+
+ auto Transformations = translateEdits(Result, Rule.Edits);
+ if (!Transformations) {
+ Consumer(Transformations.takeError());
+ return;
+ }
+
+ if (Transformations->empty()) {
+ // No rewrite applied (but no error encountered either).
+ RootLoc.print(llvm::errs() << "note: skipping match at loc ",
+ *Result.SourceManager);
+ llvm::errs() << "\n";
+ return;
+ }
+
+ // Record the results in the AtomicChange.
+ AtomicChange AC(*Result.SourceManager, RootLoc);
+ for (const auto &T : *Transformations) {
+ if (auto Err = AC.replace(*Result.SourceManager, T.Range, T.Replacement)) {
+ Consumer(std::move(Err));
+ return;
+ }
+ }
+
+ Consumer(std::move(AC));
+}
diff --git a/lib/Tooling/RefactoringCallbacks.cpp b/lib/Tooling/RefactoringCallbacks.cpp
index 9fd333ca55..2aa5b5bf9d 100644
--- a/lib/Tooling/RefactoringCallbacks.cpp
+++ b/lib/Tooling/RefactoringCallbacks.cpp
@@ -1,9 +1,8 @@
//===--- RefactoringCallbacks.cpp - Structural query framework ------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Tooling/StandaloneExecution.cpp b/lib/Tooling/StandaloneExecution.cpp
index 1daf792fb8..ad82ee083a 100644
--- a/lib/Tooling/StandaloneExecution.cpp
+++ b/lib/Tooling/StandaloneExecution.cpp
@@ -1,9 +1,8 @@
//===- lib/Tooling/Execution.cpp - Standalone clang action execution. -----===//
//
-// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index 63aa64a533..68760ef756 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -1,9 +1,8 @@
//===- Tooling.cpp - Running clang standalone tools -----------------------===//
//
-// 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
//
//===----------------------------------------------------------------------===//
//
@@ -302,7 +301,7 @@ bool ToolInvocation::run() {
DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
const std::unique_ptr<driver::Driver> Driver(
- newDriver(&Diagnostics, BinaryName, Files->getVirtualFileSystem()));
+ newDriver(&Diagnostics, BinaryName, &Files->getVirtualFileSystem()));
// The "input file not found" diagnostics from the driver are useful.
// The driver is only aware of the VFS working directory, but some clients
// change this at the FileManager level instead.