aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/clang/lib/Tooling
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Tooling')
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/ASTDiff/ASTDiff.cpp1020
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/AllTUsExecution.cpp187
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp134
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp180
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp421
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp51
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Core/Lookup.cpp191
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Core/Replacement.cpp628
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Execution.cpp108
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/FileMatchTrie.cpp196
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/FixIt.cpp31
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp330
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Inclusions/IncludeStyle.cpp31
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp547
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/JSONCompilationDatabase.cpp384
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring.cpp104
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelection.cpp451
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp48
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp365
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/Extract.cpp199
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp112
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.h52
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/RefactoringActions.cpp114
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp277
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp37
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp146
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp274
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp585
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/RefactoringCallbacks.cpp241
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/StandaloneExecution.cpp93
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp611
31 files changed, 8148 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Tooling/ASTDiff/ASTDiff.cpp b/contrib/llvm/tools/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
new file mode 100644
index 000000000000..592e8572c770
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
@@ -0,0 +1,1020 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains definitons for the AST differencing interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ASTDiff/ASTDiff.h"
+
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/PriorityQueue.h"
+
+#include <limits>
+#include <memory>
+#include <unordered_set>
+
+using namespace llvm;
+using namespace clang;
+
+namespace clang {
+namespace diff {
+
+namespace {
+/// Maps nodes of the left tree to ones on the right, and vice versa.
+class Mapping {
+public:
+ Mapping() = default;
+ Mapping(Mapping &&Other) = default;
+ Mapping &operator=(Mapping &&Other) = default;
+
+ Mapping(size_t Size) {
+ SrcToDst = llvm::make_unique<NodeId[]>(Size);
+ DstToSrc = llvm::make_unique<NodeId[]>(Size);
+ }
+
+ void link(NodeId Src, NodeId Dst) {
+ SrcToDst[Src] = Dst, DstToSrc[Dst] = Src;
+ }
+
+ NodeId getDst(NodeId Src) const { return SrcToDst[Src]; }
+ NodeId getSrc(NodeId Dst) const { return DstToSrc[Dst]; }
+ bool hasSrc(NodeId Src) const { return getDst(Src).isValid(); }
+ bool hasDst(NodeId Dst) const { return getSrc(Dst).isValid(); }
+
+private:
+ std::unique_ptr<NodeId[]> SrcToDst, DstToSrc;
+};
+} // end anonymous namespace
+
+class ASTDiff::Impl {
+public:
+ SyntaxTree::Impl &T1, &T2;
+ Mapping TheMapping;
+
+ Impl(SyntaxTree::Impl &T1, SyntaxTree::Impl &T2,
+ const ComparisonOptions &Options);
+
+ /// Matches nodes one-by-one based on their similarity.
+ void computeMapping();
+
+ // Compute Change for each node based on similarity.
+ void computeChangeKinds(Mapping &M);
+
+ NodeId getMapped(const std::unique_ptr<SyntaxTree::Impl> &Tree,
+ NodeId Id) const {
+ if (&*Tree == &T1)
+ return TheMapping.getDst(Id);
+ assert(&*Tree == &T2 && "Invalid tree.");
+ return TheMapping.getSrc(Id);
+ }
+
+private:
+ // Returns true if the two subtrees are identical.
+ bool identical(NodeId Id1, NodeId Id2) const;
+
+ // Returns false if the nodes must not be mached.
+ bool isMatchingPossible(NodeId Id1, NodeId Id2) const;
+
+ // Returns true if the nodes' parents are matched.
+ bool haveSameParents(const Mapping &M, NodeId Id1, NodeId Id2) const;
+
+ // Uses an optimal albeit slow algorithm to compute a mapping between two
+ // subtrees, but only if both have fewer nodes than MaxSize.
+ void addOptimalMapping(Mapping &M, NodeId Id1, NodeId Id2) const;
+
+ // Computes the ratio of common descendants between the two nodes.
+ // Descendants are only considered to be equal when they are mapped in M.
+ double getJaccardSimilarity(const Mapping &M, NodeId Id1, NodeId Id2) const;
+
+ // Returns the node that has the highest degree of similarity.
+ NodeId findCandidate(const Mapping &M, NodeId Id1) const;
+
+ // Returns a mapping of identical subtrees.
+ Mapping matchTopDown() const;
+
+ // Tries to match any yet unmapped nodes, in a bottom-up fashion.
+ void matchBottomUp(Mapping &M) const;
+
+ const ComparisonOptions &Options;
+
+ friend class ZhangShashaMatcher;
+};
+
+/// Represents the AST of a TranslationUnit.
+class SyntaxTree::Impl {
+public:
+ Impl(SyntaxTree *Parent, ASTContext &AST);
+ /// Constructs a tree from an AST node.
+ Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST);
+ Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST);
+ template <class T>
+ Impl(SyntaxTree *Parent,
+ typename std::enable_if<std::is_base_of<Stmt, T>::value, T>::type *Node,
+ ASTContext &AST)
+ : Impl(Parent, dyn_cast<Stmt>(Node), AST) {}
+ template <class T>
+ Impl(SyntaxTree *Parent,
+ typename std::enable_if<std::is_base_of<Decl, T>::value, T>::type *Node,
+ ASTContext &AST)
+ : Impl(Parent, dyn_cast<Decl>(Node), AST) {}
+
+ SyntaxTree *Parent;
+ ASTContext &AST;
+ PrintingPolicy TypePP;
+ /// Nodes in preorder.
+ std::vector<Node> Nodes;
+ std::vector<NodeId> Leaves;
+ // Maps preorder indices to postorder ones.
+ std::vector<int> PostorderIds;
+ std::vector<NodeId> NodesBfs;
+
+ int getSize() const { return Nodes.size(); }
+ NodeId getRootId() const { return 0; }
+ PreorderIterator begin() const { return getRootId(); }
+ PreorderIterator end() const { return getSize(); }
+
+ const Node &getNode(NodeId Id) const { return Nodes[Id]; }
+ Node &getMutableNode(NodeId Id) { return Nodes[Id]; }
+ bool isValidNodeId(NodeId Id) const { return Id >= 0 && Id < getSize(); }
+ void addNode(Node &N) { Nodes.push_back(N); }
+ int getNumberOfDescendants(NodeId Id) const;
+ bool isInSubtree(NodeId Id, NodeId SubtreeRoot) const;
+ int findPositionInParent(NodeId Id, bool Shifted = false) const;
+
+ std::string getRelativeName(const NamedDecl *ND,
+ const DeclContext *Context) const;
+ std::string getRelativeName(const NamedDecl *ND) const;
+
+ std::string getNodeValue(NodeId Id) const;
+ std::string getNodeValue(const Node &Node) const;
+ std::string getDeclValue(const Decl *D) const;
+ std::string getStmtValue(const Stmt *S) const;
+
+private:
+ void initTree();
+ void setLeftMostDescendants();
+};
+
+static bool isSpecializedNodeExcluded(const Decl *D) { return D->isImplicit(); }
+static bool isSpecializedNodeExcluded(const Stmt *S) { return false; }
+static bool isSpecializedNodeExcluded(CXXCtorInitializer *I) {
+ return !I->isWritten();
+}
+
+template <class T>
+static bool isNodeExcluded(const SourceManager &SrcMgr, T *N) {
+ if (!N)
+ return true;
+ SourceLocation SLoc = N->getSourceRange().getBegin();
+ if (SLoc.isValid()) {
+ // Ignore everything from other files.
+ if (!SrcMgr.isInMainFile(SLoc))
+ return true;
+ // Ignore macros.
+ if (SLoc != SrcMgr.getSpellingLoc(SLoc))
+ return true;
+ }
+ return isSpecializedNodeExcluded(N);
+}
+
+namespace {
+// Sets Height, Parent and Children for each node.
+struct PreorderVisitor : public RecursiveASTVisitor<PreorderVisitor> {
+ int Id = 0, Depth = 0;
+ NodeId Parent;
+ SyntaxTree::Impl &Tree;
+
+ PreorderVisitor(SyntaxTree::Impl &Tree) : Tree(Tree) {}
+
+ template <class T> std::tuple<NodeId, NodeId> PreTraverse(T *ASTNode) {
+ NodeId MyId = Id;
+ Tree.Nodes.emplace_back();
+ Node &N = Tree.getMutableNode(MyId);
+ N.Parent = Parent;
+ N.Depth = Depth;
+ N.ASTNode = DynTypedNode::create(*ASTNode);
+ assert(!N.ASTNode.getNodeKind().isNone() &&
+ "Expected nodes to have a valid kind.");
+ if (Parent.isValid()) {
+ Node &P = Tree.getMutableNode(Parent);
+ P.Children.push_back(MyId);
+ }
+ Parent = MyId;
+ ++Id;
+ ++Depth;
+ return std::make_tuple(MyId, Tree.getNode(MyId).Parent);
+ }
+ void PostTraverse(std::tuple<NodeId, NodeId> State) {
+ NodeId MyId, PreviousParent;
+ std::tie(MyId, PreviousParent) = State;
+ assert(MyId.isValid() && "Expecting to only traverse valid nodes.");
+ Parent = PreviousParent;
+ --Depth;
+ Node &N = Tree.getMutableNode(MyId);
+ N.RightMostDescendant = Id - 1;
+ assert(N.RightMostDescendant >= 0 &&
+ N.RightMostDescendant < Tree.getSize() &&
+ "Rightmost descendant must be a valid tree node.");
+ if (N.isLeaf())
+ Tree.Leaves.push_back(MyId);
+ N.Height = 1;
+ for (NodeId Child : N.Children)
+ N.Height = std::max(N.Height, 1 + Tree.getNode(Child).Height);
+ }
+ bool TraverseDecl(Decl *D) {
+ if (isNodeExcluded(Tree.AST.getSourceManager(), D))
+ return true;
+ auto SavedState = PreTraverse(D);
+ RecursiveASTVisitor<PreorderVisitor>::TraverseDecl(D);
+ PostTraverse(SavedState);
+ return true;
+ }
+ bool TraverseStmt(Stmt *S) {
+ if (S)
+ S = S->IgnoreImplicit();
+ if (isNodeExcluded(Tree.AST.getSourceManager(), S))
+ return true;
+ auto SavedState = PreTraverse(S);
+ RecursiveASTVisitor<PreorderVisitor>::TraverseStmt(S);
+ PostTraverse(SavedState);
+ return true;
+ }
+ bool TraverseType(QualType T) { return true; }
+ bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
+ if (isNodeExcluded(Tree.AST.getSourceManager(), Init))
+ return true;
+ auto SavedState = PreTraverse(Init);
+ RecursiveASTVisitor<PreorderVisitor>::TraverseConstructorInitializer(Init);
+ PostTraverse(SavedState);
+ return true;
+ }
+};
+} // end anonymous namespace
+
+SyntaxTree::Impl::Impl(SyntaxTree *Parent, ASTContext &AST)
+ : Parent(Parent), AST(AST), TypePP(AST.getLangOpts()) {
+ TypePP.AnonymousTagLocations = false;
+}
+
+SyntaxTree::Impl::Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST)
+ : Impl(Parent, AST) {
+ PreorderVisitor PreorderWalker(*this);
+ PreorderWalker.TraverseDecl(N);
+ initTree();
+}
+
+SyntaxTree::Impl::Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST)
+ : Impl(Parent, AST) {
+ PreorderVisitor PreorderWalker(*this);
+ PreorderWalker.TraverseStmt(N);
+ initTree();
+}
+
+static std::vector<NodeId> getSubtreePostorder(const SyntaxTree::Impl &Tree,
+ NodeId Root) {
+ std::vector<NodeId> Postorder;
+ std::function<void(NodeId)> Traverse = [&](NodeId Id) {
+ const Node &N = Tree.getNode(Id);
+ for (NodeId Child : N.Children)
+ Traverse(Child);
+ Postorder.push_back(Id);
+ };
+ Traverse(Root);
+ return Postorder;
+}
+
+static std::vector<NodeId> getSubtreeBfs(const SyntaxTree::Impl &Tree,
+ NodeId Root) {
+ std::vector<NodeId> Ids;
+ size_t Expanded = 0;
+ Ids.push_back(Root);
+ while (Expanded < Ids.size())
+ for (NodeId Child : Tree.getNode(Ids[Expanded++]).Children)
+ Ids.push_back(Child);
+ return Ids;
+}
+
+void SyntaxTree::Impl::initTree() {
+ setLeftMostDescendants();
+ int PostorderId = 0;
+ PostorderIds.resize(getSize());
+ std::function<void(NodeId)> PostorderTraverse = [&](NodeId Id) {
+ for (NodeId Child : getNode(Id).Children)
+ PostorderTraverse(Child);
+ PostorderIds[Id] = PostorderId;
+ ++PostorderId;
+ };
+ PostorderTraverse(getRootId());
+ NodesBfs = getSubtreeBfs(*this, getRootId());
+}
+
+void SyntaxTree::Impl::setLeftMostDescendants() {
+ for (NodeId Leaf : Leaves) {
+ getMutableNode(Leaf).LeftMostDescendant = Leaf;
+ NodeId Parent, Cur = Leaf;
+ while ((Parent = getNode(Cur).Parent).isValid() &&
+ getNode(Parent).Children[0] == Cur) {
+ Cur = Parent;
+ getMutableNode(Cur).LeftMostDescendant = Leaf;
+ }
+ }
+}
+
+int SyntaxTree::Impl::getNumberOfDescendants(NodeId Id) const {
+ return getNode(Id).RightMostDescendant - Id + 1;
+}
+
+bool SyntaxTree::Impl::isInSubtree(NodeId Id, NodeId SubtreeRoot) const {
+ return Id >= SubtreeRoot && Id <= getNode(SubtreeRoot).RightMostDescendant;
+}
+
+int SyntaxTree::Impl::findPositionInParent(NodeId Id, bool Shifted) const {
+ NodeId Parent = getNode(Id).Parent;
+ if (Parent.isInvalid())
+ return 0;
+ const auto &Siblings = getNode(Parent).Children;
+ int Position = 0;
+ for (size_t I = 0, E = Siblings.size(); I < E; ++I) {
+ if (Shifted)
+ Position += getNode(Siblings[I]).Shift;
+ if (Siblings[I] == Id) {
+ Position += I;
+ return Position;
+ }
+ }
+ llvm_unreachable("Node not found in parent's children.");
+}
+
+// Returns the qualified name of ND. If it is subordinate to Context,
+// then the prefix of the latter is removed from the returned value.
+std::string
+SyntaxTree::Impl::getRelativeName(const NamedDecl *ND,
+ const DeclContext *Context) const {
+ std::string Val = ND->getQualifiedNameAsString();
+ std::string ContextPrefix;
+ if (!Context)
+ return Val;
+ if (auto *Namespace = dyn_cast<NamespaceDecl>(Context))
+ ContextPrefix = Namespace->getQualifiedNameAsString();
+ else if (auto *Record = dyn_cast<RecordDecl>(Context))
+ ContextPrefix = Record->getQualifiedNameAsString();
+ else if (AST.getLangOpts().CPlusPlus11)
+ if (auto *Tag = dyn_cast<TagDecl>(Context))
+ ContextPrefix = Tag->getQualifiedNameAsString();
+ // Strip the qualifier, if Val refers to something in the current scope.
+ // But leave one leading ':' in place, so that we know that this is a
+ // relative path.
+ if (!ContextPrefix.empty() && StringRef(Val).startswith(ContextPrefix))
+ Val = Val.substr(ContextPrefix.size() + 1);
+ return Val;
+}
+
+std::string SyntaxTree::Impl::getRelativeName(const NamedDecl *ND) const {
+ return getRelativeName(ND, ND->getDeclContext());
+}
+
+static const DeclContext *getEnclosingDeclContext(ASTContext &AST,
+ const Stmt *S) {
+ while (S) {
+ const auto &Parents = AST.getParents(*S);
+ if (Parents.empty())
+ return nullptr;
+ const auto &P = Parents[0];
+ if (const auto *D = P.get<Decl>())
+ return D->getDeclContext();
+ S = P.get<Stmt>();
+ }
+ return nullptr;
+}
+
+static std::string getInitializerValue(const CXXCtorInitializer *Init,
+ const PrintingPolicy &TypePP) {
+ if (Init->isAnyMemberInitializer())
+ return Init->getAnyMember()->getName();
+ if (Init->isBaseInitializer())
+ return QualType(Init->getBaseClass(), 0).getAsString(TypePP);
+ if (Init->isDelegatingInitializer())
+ return Init->getTypeSourceInfo()->getType().getAsString(TypePP);
+ llvm_unreachable("Unknown initializer type");
+}
+
+std::string SyntaxTree::Impl::getNodeValue(NodeId Id) const {
+ return getNodeValue(getNode(Id));
+}
+
+std::string SyntaxTree::Impl::getNodeValue(const Node &N) const {
+ const DynTypedNode &DTN = N.ASTNode;
+ if (auto *S = DTN.get<Stmt>())
+ return getStmtValue(S);
+ if (auto *D = DTN.get<Decl>())
+ return getDeclValue(D);
+ if (auto *Init = DTN.get<CXXCtorInitializer>())
+ return getInitializerValue(Init, TypePP);
+ llvm_unreachable("Fatal: unhandled AST node.\n");
+}
+
+std::string SyntaxTree::Impl::getDeclValue(const Decl *D) const {
+ std::string Value;
+ if (auto *V = dyn_cast<ValueDecl>(D))
+ return getRelativeName(V) + "(" + V->getType().getAsString(TypePP) + ")";
+ if (auto *N = dyn_cast<NamedDecl>(D))
+ Value += getRelativeName(N) + ";";
+ if (auto *T = dyn_cast<TypedefNameDecl>(D))
+ return Value + T->getUnderlyingType().getAsString(TypePP) + ";";
+ if (auto *T = dyn_cast<TypeDecl>(D))
+ if (T->getTypeForDecl())
+ Value +=
+ T->getTypeForDecl()->getCanonicalTypeInternal().getAsString(TypePP) +
+ ";";
+ if (auto *U = dyn_cast<UsingDirectiveDecl>(D))
+ return U->getNominatedNamespace()->getName();
+ if (auto *A = dyn_cast<AccessSpecDecl>(D)) {
+ CharSourceRange Range(A->getSourceRange(), false);
+ return Lexer::getSourceText(Range, AST.getSourceManager(),
+ AST.getLangOpts());
+ }
+ return Value;
+}
+
+std::string SyntaxTree::Impl::getStmtValue(const Stmt *S) const {
+ if (auto *U = dyn_cast<UnaryOperator>(S))
+ return UnaryOperator::getOpcodeStr(U->getOpcode());
+ if (auto *B = dyn_cast<BinaryOperator>(S))
+ return B->getOpcodeStr();
+ if (auto *M = dyn_cast<MemberExpr>(S))
+ return getRelativeName(M->getMemberDecl());
+ if (auto *I = dyn_cast<IntegerLiteral>(S)) {
+ SmallString<256> Str;
+ I->getValue().toString(Str, /*Radix=*/10, /*Signed=*/false);
+ return Str.str();
+ }
+ if (auto *F = dyn_cast<FloatingLiteral>(S)) {
+ SmallString<256> Str;
+ F->getValue().toString(Str);
+ return Str.str();
+ }
+ if (auto *D = dyn_cast<DeclRefExpr>(S))
+ return getRelativeName(D->getDecl(), getEnclosingDeclContext(AST, S));
+ if (auto *String = dyn_cast<StringLiteral>(S))
+ return String->getString();
+ if (auto *B = dyn_cast<CXXBoolLiteralExpr>(S))
+ return B->getValue() ? "true" : "false";
+ return "";
+}
+
+/// Identifies a node in a subtree by its postorder offset, starting at 1.
+struct SNodeId {
+ int Id = 0;
+
+ explicit SNodeId(int Id) : Id(Id) {}
+ explicit SNodeId() = default;
+
+ operator int() const { return Id; }
+ SNodeId &operator++() { return ++Id, *this; }
+ SNodeId &operator--() { return --Id, *this; }
+ SNodeId operator+(int Other) const { return SNodeId(Id + Other); }
+};
+
+class Subtree {
+private:
+ /// The parent tree.
+ const SyntaxTree::Impl &Tree;
+ /// Maps SNodeIds to original ids.
+ std::vector<NodeId> RootIds;
+ /// Maps subtree nodes to their leftmost descendants wtihin the subtree.
+ std::vector<SNodeId> LeftMostDescendants;
+
+public:
+ std::vector<SNodeId> KeyRoots;
+
+ Subtree(const SyntaxTree::Impl &Tree, NodeId SubtreeRoot) : Tree(Tree) {
+ RootIds = getSubtreePostorder(Tree, SubtreeRoot);
+ int NumLeaves = setLeftMostDescendants();
+ computeKeyRoots(NumLeaves);
+ }
+ int getSize() const { return RootIds.size(); }
+ NodeId getIdInRoot(SNodeId Id) const {
+ assert(Id > 0 && Id <= getSize() && "Invalid subtree node index.");
+ return RootIds[Id - 1];
+ }
+ const Node &getNode(SNodeId Id) const {
+ return Tree.getNode(getIdInRoot(Id));
+ }
+ SNodeId getLeftMostDescendant(SNodeId Id) const {
+ assert(Id > 0 && Id <= getSize() && "Invalid subtree node index.");
+ return LeftMostDescendants[Id - 1];
+ }
+ /// Returns the postorder index of the leftmost descendant in the subtree.
+ NodeId getPostorderOffset() const {
+ return Tree.PostorderIds[getIdInRoot(SNodeId(1))];
+ }
+ std::string getNodeValue(SNodeId Id) const {
+ return Tree.getNodeValue(getIdInRoot(Id));
+ }
+
+private:
+ /// Returns the number of leafs in the subtree.
+ int setLeftMostDescendants() {
+ int NumLeaves = 0;
+ LeftMostDescendants.resize(getSize());
+ for (int I = 0; I < getSize(); ++I) {
+ SNodeId SI(I + 1);
+ const Node &N = getNode(SI);
+ NumLeaves += N.isLeaf();
+ assert(I == Tree.PostorderIds[getIdInRoot(SI)] - getPostorderOffset() &&
+ "Postorder traversal in subtree should correspond to traversal in "
+ "the root tree by a constant offset.");
+ LeftMostDescendants[I] = SNodeId(Tree.PostorderIds[N.LeftMostDescendant] -
+ getPostorderOffset());
+ }
+ return NumLeaves;
+ }
+ void computeKeyRoots(int Leaves) {
+ KeyRoots.resize(Leaves);
+ std::unordered_set<int> Visited;
+ int K = Leaves - 1;
+ for (SNodeId I(getSize()); I > 0; --I) {
+ SNodeId LeftDesc = getLeftMostDescendant(I);
+ if (Visited.count(LeftDesc))
+ continue;
+ assert(K >= 0 && "K should be non-negative");
+ KeyRoots[K] = I;
+ Visited.insert(LeftDesc);
+ --K;
+ }
+ }
+};
+
+/// Implementation of Zhang and Shasha's Algorithm for tree edit distance.
+/// Computes an optimal mapping between two trees using only insertion,
+/// deletion and update as edit actions (similar to the Levenshtein distance).
+class ZhangShashaMatcher {
+ const ASTDiff::Impl &DiffImpl;
+ Subtree S1;
+ Subtree S2;
+ std::unique_ptr<std::unique_ptr<double[]>[]> TreeDist, ForestDist;
+
+public:
+ ZhangShashaMatcher(const ASTDiff::Impl &DiffImpl, const SyntaxTree::Impl &T1,
+ const SyntaxTree::Impl &T2, NodeId Id1, NodeId Id2)
+ : DiffImpl(DiffImpl), S1(T1, Id1), S2(T2, Id2) {
+ TreeDist = llvm::make_unique<std::unique_ptr<double[]>[]>(
+ size_t(S1.getSize()) + 1);
+ ForestDist = llvm::make_unique<std::unique_ptr<double[]>[]>(
+ size_t(S1.getSize()) + 1);
+ for (int I = 0, E = S1.getSize() + 1; I < E; ++I) {
+ TreeDist[I] = llvm::make_unique<double[]>(size_t(S2.getSize()) + 1);
+ ForestDist[I] = llvm::make_unique<double[]>(size_t(S2.getSize()) + 1);
+ }
+ }
+
+ std::vector<std::pair<NodeId, NodeId>> getMatchingNodes() {
+ std::vector<std::pair<NodeId, NodeId>> Matches;
+ std::vector<std::pair<SNodeId, SNodeId>> TreePairs;
+
+ computeTreeDist();
+
+ bool RootNodePair = true;
+
+ TreePairs.emplace_back(SNodeId(S1.getSize()), SNodeId(S2.getSize()));
+
+ while (!TreePairs.empty()) {
+ SNodeId LastRow, LastCol, FirstRow, FirstCol, Row, Col;
+ std::tie(LastRow, LastCol) = TreePairs.back();
+ TreePairs.pop_back();
+
+ if (!RootNodePair) {
+ computeForestDist(LastRow, LastCol);
+ }
+
+ RootNodePair = false;
+
+ FirstRow = S1.getLeftMostDescendant(LastRow);
+ FirstCol = S2.getLeftMostDescendant(LastCol);
+
+ Row = LastRow;
+ Col = LastCol;
+
+ while (Row > FirstRow || Col > FirstCol) {
+ if (Row > FirstRow &&
+ ForestDist[Row - 1][Col] + 1 == ForestDist[Row][Col]) {
+ --Row;
+ } else if (Col > FirstCol &&
+ ForestDist[Row][Col - 1] + 1 == ForestDist[Row][Col]) {
+ --Col;
+ } else {
+ SNodeId LMD1 = S1.getLeftMostDescendant(Row);
+ SNodeId LMD2 = S2.getLeftMostDescendant(Col);
+ if (LMD1 == S1.getLeftMostDescendant(LastRow) &&
+ LMD2 == S2.getLeftMostDescendant(LastCol)) {
+ NodeId Id1 = S1.getIdInRoot(Row);
+ NodeId Id2 = S2.getIdInRoot(Col);
+ assert(DiffImpl.isMatchingPossible(Id1, Id2) &&
+ "These nodes must not be matched.");
+ Matches.emplace_back(Id1, Id2);
+ --Row;
+ --Col;
+ } else {
+ TreePairs.emplace_back(Row, Col);
+ Row = LMD1;
+ Col = LMD2;
+ }
+ }
+ }
+ }
+ return Matches;
+ }
+
+private:
+ /// We use a simple cost model for edit actions, which seems good enough.
+ /// Simple cost model for edit actions. This seems to make the matching
+ /// algorithm perform reasonably well.
+ /// The values range between 0 and 1, or infinity if this edit action should
+ /// always be avoided.
+ static constexpr double DeletionCost = 1;
+ static constexpr double InsertionCost = 1;
+
+ double getUpdateCost(SNodeId Id1, SNodeId Id2) {
+ if (!DiffImpl.isMatchingPossible(S1.getIdInRoot(Id1), S2.getIdInRoot(Id2)))
+ return std::numeric_limits<double>::max();
+ return S1.getNodeValue(Id1) != S2.getNodeValue(Id2);
+ }
+
+ void computeTreeDist() {
+ for (SNodeId Id1 : S1.KeyRoots)
+ for (SNodeId Id2 : S2.KeyRoots)
+ computeForestDist(Id1, Id2);
+ }
+
+ void computeForestDist(SNodeId Id1, SNodeId Id2) {
+ assert(Id1 > 0 && Id2 > 0 && "Expecting offsets greater than 0.");
+ SNodeId LMD1 = S1.getLeftMostDescendant(Id1);
+ SNodeId LMD2 = S2.getLeftMostDescendant(Id2);
+
+ ForestDist[LMD1][LMD2] = 0;
+ for (SNodeId D1 = LMD1 + 1; D1 <= Id1; ++D1) {
+ ForestDist[D1][LMD2] = ForestDist[D1 - 1][LMD2] + DeletionCost;
+ for (SNodeId D2 = LMD2 + 1; D2 <= Id2; ++D2) {
+ ForestDist[LMD1][D2] = ForestDist[LMD1][D2 - 1] + InsertionCost;
+ SNodeId DLMD1 = S1.getLeftMostDescendant(D1);
+ SNodeId DLMD2 = S2.getLeftMostDescendant(D2);
+ if (DLMD1 == LMD1 && DLMD2 == LMD2) {
+ double UpdateCost = getUpdateCost(D1, D2);
+ ForestDist[D1][D2] =
+ std::min({ForestDist[D1 - 1][D2] + DeletionCost,
+ ForestDist[D1][D2 - 1] + InsertionCost,
+ ForestDist[D1 - 1][D2 - 1] + UpdateCost});
+ TreeDist[D1][D2] = ForestDist[D1][D2];
+ } else {
+ ForestDist[D1][D2] =
+ std::min({ForestDist[D1 - 1][D2] + DeletionCost,
+ ForestDist[D1][D2 - 1] + InsertionCost,
+ ForestDist[DLMD1][DLMD2] + TreeDist[D1][D2]});
+ }
+ }
+ }
+ }
+};
+
+ast_type_traits::ASTNodeKind Node::getType() const {
+ return ASTNode.getNodeKind();
+}
+
+StringRef Node::getTypeLabel() const { return getType().asStringRef(); }
+
+llvm::Optional<std::string> Node::getQualifiedIdentifier() const {
+ if (auto *ND = ASTNode.get<NamedDecl>()) {
+ if (ND->getDeclName().isIdentifier())
+ return ND->getQualifiedNameAsString();
+ }
+ return llvm::None;
+}
+
+llvm::Optional<StringRef> Node::getIdentifier() const {
+ if (auto *ND = ASTNode.get<NamedDecl>()) {
+ if (ND->getDeclName().isIdentifier())
+ return ND->getName();
+ }
+ return llvm::None;
+}
+
+namespace {
+// Compares nodes by their depth.
+struct HeightLess {
+ const SyntaxTree::Impl &Tree;
+ HeightLess(const SyntaxTree::Impl &Tree) : Tree(Tree) {}
+ bool operator()(NodeId Id1, NodeId Id2) const {
+ return Tree.getNode(Id1).Height < Tree.getNode(Id2).Height;
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// Priority queue for nodes, sorted descendingly by their height.
+class PriorityList {
+ const SyntaxTree::Impl &Tree;
+ HeightLess Cmp;
+ std::vector<NodeId> Container;
+ PriorityQueue<NodeId, std::vector<NodeId>, HeightLess> List;
+
+public:
+ PriorityList(const SyntaxTree::Impl &Tree)
+ : Tree(Tree), Cmp(Tree), List(Cmp, Container) {}
+
+ void push(NodeId id) { List.push(id); }
+
+ std::vector<NodeId> pop() {
+ int Max = peekMax();
+ std::vector<NodeId> Result;
+ if (Max == 0)
+ return Result;
+ while (peekMax() == Max) {
+ Result.push_back(List.top());
+ List.pop();
+ }
+ // TODO this is here to get a stable output, not a good heuristic
+ llvm::sort(Result);
+ return Result;
+ }
+ int peekMax() const {
+ if (List.empty())
+ return 0;
+ return Tree.getNode(List.top()).Height;
+ }
+ void open(NodeId Id) {
+ for (NodeId Child : Tree.getNode(Id).Children)
+ push(Child);
+ }
+};
+} // end anonymous namespace
+
+bool ASTDiff::Impl::identical(NodeId Id1, NodeId Id2) const {
+ const Node &N1 = T1.getNode(Id1);
+ const Node &N2 = T2.getNode(Id2);
+ if (N1.Children.size() != N2.Children.size() ||
+ !isMatchingPossible(Id1, Id2) ||
+ T1.getNodeValue(Id1) != T2.getNodeValue(Id2))
+ return false;
+ for (size_t Id = 0, E = N1.Children.size(); Id < E; ++Id)
+ if (!identical(N1.Children[Id], N2.Children[Id]))
+ return false;
+ return true;
+}
+
+bool ASTDiff::Impl::isMatchingPossible(NodeId Id1, NodeId Id2) const {
+ return Options.isMatchingAllowed(T1.getNode(Id1), T2.getNode(Id2));
+}
+
+bool ASTDiff::Impl::haveSameParents(const Mapping &M, NodeId Id1,
+ NodeId Id2) const {
+ NodeId P1 = T1.getNode(Id1).Parent;
+ NodeId P2 = T2.getNode(Id2).Parent;
+ return (P1.isInvalid() && P2.isInvalid()) ||
+ (P1.isValid() && P2.isValid() && M.getDst(P1) == P2);
+}
+
+void ASTDiff::Impl::addOptimalMapping(Mapping &M, NodeId Id1,
+ NodeId Id2) const {
+ if (std::max(T1.getNumberOfDescendants(Id1), T2.getNumberOfDescendants(Id2)) >
+ Options.MaxSize)
+ return;
+ ZhangShashaMatcher Matcher(*this, T1, T2, Id1, Id2);
+ std::vector<std::pair<NodeId, NodeId>> R = Matcher.getMatchingNodes();
+ for (const auto Tuple : R) {
+ NodeId Src = Tuple.first;
+ NodeId Dst = Tuple.second;
+ if (!M.hasSrc(Src) && !M.hasDst(Dst))
+ M.link(Src, Dst);
+ }
+}
+
+double ASTDiff::Impl::getJaccardSimilarity(const Mapping &M, NodeId Id1,
+ NodeId Id2) const {
+ int CommonDescendants = 0;
+ const Node &N1 = T1.getNode(Id1);
+ // Count the common descendants, excluding the subtree root.
+ for (NodeId Src = Id1 + 1; Src <= N1.RightMostDescendant; ++Src) {
+ NodeId Dst = M.getDst(Src);
+ CommonDescendants += int(Dst.isValid() && T2.isInSubtree(Dst, Id2));
+ }
+ // We need to subtract 1 to get the number of descendants excluding the root.
+ double Denominator = T1.getNumberOfDescendants(Id1) - 1 +
+ T2.getNumberOfDescendants(Id2) - 1 - CommonDescendants;
+ // CommonDescendants is less than the size of one subtree.
+ assert(Denominator >= 0 && "Expected non-negative denominator.");
+ if (Denominator == 0)
+ return 0;
+ return CommonDescendants / Denominator;
+}
+
+NodeId ASTDiff::Impl::findCandidate(const Mapping &M, NodeId Id1) const {
+ NodeId Candidate;
+ double HighestSimilarity = 0.0;
+ for (NodeId Id2 : T2) {
+ if (!isMatchingPossible(Id1, Id2))
+ continue;
+ if (M.hasDst(Id2))
+ continue;
+ double Similarity = getJaccardSimilarity(M, Id1, Id2);
+ if (Similarity >= Options.MinSimilarity && Similarity > HighestSimilarity) {
+ HighestSimilarity = Similarity;
+ Candidate = Id2;
+ }
+ }
+ return Candidate;
+}
+
+void ASTDiff::Impl::matchBottomUp(Mapping &M) const {
+ std::vector<NodeId> Postorder = getSubtreePostorder(T1, T1.getRootId());
+ for (NodeId Id1 : Postorder) {
+ if (Id1 == T1.getRootId() && !M.hasSrc(T1.getRootId()) &&
+ !M.hasDst(T2.getRootId())) {
+ if (isMatchingPossible(T1.getRootId(), T2.getRootId())) {
+ M.link(T1.getRootId(), T2.getRootId());
+ addOptimalMapping(M, T1.getRootId(), T2.getRootId());
+ }
+ break;
+ }
+ bool Matched = M.hasSrc(Id1);
+ const Node &N1 = T1.getNode(Id1);
+ bool MatchedChildren = llvm::any_of(
+ N1.Children, [&](NodeId Child) { return M.hasSrc(Child); });
+ if (Matched || !MatchedChildren)
+ continue;
+ NodeId Id2 = findCandidate(M, Id1);
+ if (Id2.isValid()) {
+ M.link(Id1, Id2);
+ addOptimalMapping(M, Id1, Id2);
+ }
+ }
+}
+
+Mapping ASTDiff::Impl::matchTopDown() const {
+ PriorityList L1(T1);
+ PriorityList L2(T2);
+
+ Mapping M(T1.getSize() + T2.getSize());
+
+ L1.push(T1.getRootId());
+ L2.push(T2.getRootId());
+
+ int Max1, Max2;
+ while (std::min(Max1 = L1.peekMax(), Max2 = L2.peekMax()) >
+ Options.MinHeight) {
+ if (Max1 > Max2) {
+ for (NodeId Id : L1.pop())
+ L1.open(Id);
+ continue;
+ }
+ if (Max2 > Max1) {
+ for (NodeId Id : L2.pop())
+ L2.open(Id);
+ continue;
+ }
+ std::vector<NodeId> H1, H2;
+ H1 = L1.pop();
+ H2 = L2.pop();
+ for (NodeId Id1 : H1) {
+ for (NodeId Id2 : H2) {
+ if (identical(Id1, Id2) && !M.hasSrc(Id1) && !M.hasDst(Id2)) {
+ for (int I = 0, E = T1.getNumberOfDescendants(Id1); I < E; ++I)
+ M.link(Id1 + I, Id2 + I);
+ }
+ }
+ }
+ for (NodeId Id1 : H1) {
+ if (!M.hasSrc(Id1))
+ L1.open(Id1);
+ }
+ for (NodeId Id2 : H2) {
+ if (!M.hasDst(Id2))
+ L2.open(Id2);
+ }
+ }
+ return M;
+}
+
+ASTDiff::Impl::Impl(SyntaxTree::Impl &T1, SyntaxTree::Impl &T2,
+ const ComparisonOptions &Options)
+ : T1(T1), T2(T2), Options(Options) {
+ computeMapping();
+ computeChangeKinds(TheMapping);
+}
+
+void ASTDiff::Impl::computeMapping() {
+ TheMapping = matchTopDown();
+ if (Options.StopAfterTopDown)
+ return;
+ matchBottomUp(TheMapping);
+}
+
+void ASTDiff::Impl::computeChangeKinds(Mapping &M) {
+ for (NodeId Id1 : T1) {
+ if (!M.hasSrc(Id1)) {
+ T1.getMutableNode(Id1).Change = Delete;
+ T1.getMutableNode(Id1).Shift -= 1;
+ }
+ }
+ for (NodeId Id2 : T2) {
+ if (!M.hasDst(Id2)) {
+ T2.getMutableNode(Id2).Change = Insert;
+ T2.getMutableNode(Id2).Shift -= 1;
+ }
+ }
+ for (NodeId Id1 : T1.NodesBfs) {
+ NodeId Id2 = M.getDst(Id1);
+ if (Id2.isInvalid())
+ continue;
+ if (!haveSameParents(M, Id1, Id2) ||
+ T1.findPositionInParent(Id1, true) !=
+ T2.findPositionInParent(Id2, true)) {
+ T1.getMutableNode(Id1).Shift -= 1;
+ T2.getMutableNode(Id2).Shift -= 1;
+ }
+ }
+ for (NodeId Id2 : T2.NodesBfs) {
+ NodeId Id1 = M.getSrc(Id2);
+ if (Id1.isInvalid())
+ continue;
+ Node &N1 = T1.getMutableNode(Id1);
+ Node &N2 = T2.getMutableNode(Id2);
+ if (Id1.isInvalid())
+ continue;
+ if (!haveSameParents(M, Id1, Id2) ||
+ T1.findPositionInParent(Id1, true) !=
+ T2.findPositionInParent(Id2, true)) {
+ N1.Change = N2.Change = Move;
+ }
+ if (T1.getNodeValue(Id1) != T2.getNodeValue(Id2)) {
+ N1.Change = N2.Change = (N1.Change == Move ? UpdateMove : Update);
+ }
+ }
+}
+
+ASTDiff::ASTDiff(SyntaxTree &T1, SyntaxTree &T2,
+ const ComparisonOptions &Options)
+ : DiffImpl(llvm::make_unique<Impl>(*T1.TreeImpl, *T2.TreeImpl, Options)) {}
+
+ASTDiff::~ASTDiff() = default;
+
+NodeId ASTDiff::getMapped(const SyntaxTree &SourceTree, NodeId Id) const {
+ return DiffImpl->getMapped(SourceTree.TreeImpl, Id);
+}
+
+SyntaxTree::SyntaxTree(ASTContext &AST)
+ : TreeImpl(llvm::make_unique<SyntaxTree::Impl>(
+ this, AST.getTranslationUnitDecl(), AST)) {}
+
+SyntaxTree::~SyntaxTree() = default;
+
+const ASTContext &SyntaxTree::getASTContext() const { return TreeImpl->AST; }
+
+const Node &SyntaxTree::getNode(NodeId Id) const {
+ return TreeImpl->getNode(Id);
+}
+
+int SyntaxTree::getSize() const { return TreeImpl->getSize(); }
+NodeId SyntaxTree::getRootId() const { return TreeImpl->getRootId(); }
+SyntaxTree::PreorderIterator SyntaxTree::begin() const {
+ return TreeImpl->begin();
+}
+SyntaxTree::PreorderIterator SyntaxTree::end() const { return TreeImpl->end(); }
+
+int SyntaxTree::findPositionInParent(NodeId Id) const {
+ return TreeImpl->findPositionInParent(Id);
+}
+
+std::pair<unsigned, unsigned>
+SyntaxTree::getSourceRangeOffsets(const Node &N) const {
+ const SourceManager &SrcMgr = TreeImpl->AST.getSourceManager();
+ SourceRange Range = N.ASTNode.getSourceRange();
+ SourceLocation BeginLoc = Range.getBegin();
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Range.getEnd(), /*Offset=*/0, SrcMgr, TreeImpl->AST.getLangOpts());
+ if (auto *ThisExpr = N.ASTNode.get<CXXThisExpr>()) {
+ if (ThisExpr->isImplicit())
+ EndLoc = BeginLoc;
+ }
+ unsigned Begin = SrcMgr.getFileOffset(SrcMgr.getExpansionLoc(BeginLoc));
+ unsigned End = SrcMgr.getFileOffset(SrcMgr.getExpansionLoc(EndLoc));
+ return {Begin, End};
+}
+
+std::string SyntaxTree::getNodeValue(NodeId Id) const {
+ return TreeImpl->getNodeValue(Id);
+}
+
+std::string SyntaxTree::getNodeValue(const Node &N) const {
+ return TreeImpl->getNodeValue(N);
+}
+
+} // end namespace diff
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/AllTUsExecution.cpp b/contrib/llvm/tools/clang/lib/Tooling/AllTUsExecution.cpp
new file mode 100644
index 000000000000..0f172b782963
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/AllTUsExecution.cpp
@@ -0,0 +1,187 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/AllTUsExecution.h"
+#include "clang/Tooling/ToolExecutorPluginRegistry.h"
+#include "llvm/Support/ThreadPool.h"
+
+namespace clang {
+namespace tooling {
+
+const char *AllTUsToolExecutor::ExecutorName = "AllTUsToolExecutor";
+
+namespace {
+llvm::Error make_string_error(const llvm::Twine &Message) {
+ return llvm::make_error<llvm::StringError>(Message,
+ llvm::inconvertibleErrorCode());
+}
+
+ArgumentsAdjuster getDefaultArgumentsAdjusters() {
+ return combineAdjusters(
+ getClangStripOutputAdjuster(),
+ combineAdjusters(getClangSyntaxOnlyAdjuster(),
+ getClangStripDependencyFileAdjuster()));
+}
+
+class ThreadSafeToolResults : public ToolResults {
+public:
+ void addResult(StringRef Key, StringRef Value) override {
+ std::unique_lock<std::mutex> LockGuard(Mutex);
+ Results.addResult(Key, Value);
+ }
+
+ std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
+ AllKVResults() override {
+ return Results.AllKVResults();
+ }
+
+ void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>
+ Callback) override {
+ Results.forEachResult(Callback);
+ }
+
+private:
+ InMemoryToolResults Results;
+ std::mutex Mutex;
+};
+
+} // namespace
+
+llvm::cl::opt<std::string>
+ Filter("filter",
+ llvm::cl::desc("Only process files that match this filter. "
+ "This flag only applies to all-TUs."),
+ llvm::cl::init(".*"));
+
+AllTUsToolExecutor::AllTUsToolExecutor(
+ const CompilationDatabase &Compilations, unsigned ThreadCount,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps)
+ : Compilations(Compilations), Results(new ThreadSafeToolResults),
+ Context(Results.get()), ThreadCount(ThreadCount) {}
+
+AllTUsToolExecutor::AllTUsToolExecutor(
+ CommonOptionsParser Options, unsigned ThreadCount,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps)
+ : OptionsParser(std::move(Options)),
+ Compilations(OptionsParser->getCompilations()),
+ Results(new ThreadSafeToolResults), Context(Results.get()),
+ ThreadCount(ThreadCount) {}
+
+llvm::Error AllTUsToolExecutor::execute(
+ llvm::ArrayRef<
+ std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
+ Actions) {
+ if (Actions.empty())
+ return make_string_error("No action to execute.");
+
+ if (Actions.size() != 1)
+ return make_string_error(
+ "Only support executing exactly 1 action at this point.");
+
+ std::string ErrorMsg;
+ std::mutex TUMutex;
+ auto AppendError = [&](llvm::Twine Err) {
+ std::unique_lock<std::mutex> LockGuard(TUMutex);
+ ErrorMsg += Err.str();
+ };
+
+ auto Log = [&](llvm::Twine Msg) {
+ std::unique_lock<std::mutex> LockGuard(TUMutex);
+ llvm::errs() << Msg.str() << "\n";
+ };
+
+ std::vector<std::string> Files;
+ llvm::Regex RegexFilter(Filter);
+ for (const auto& File : Compilations.getAllFiles()) {
+ if (RegexFilter.match(File))
+ Files.push_back(File);
+ }
+ // Add a counter to track the progress.
+ const std::string TotalNumStr = std::to_string(Files.size());
+ unsigned Counter = 0;
+ auto Count = [&]() {
+ std::unique_lock<std::mutex> LockGuard(TUMutex);
+ return ++Counter;
+ };
+
+ auto &Action = Actions.front();
+
+ {
+ 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});
+ 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");
+ },
+ File);
+ }
+ // 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())
+ return make_string_error(ErrorMsg);
+
+ return llvm::Error::success();
+}
+
+static llvm::cl::opt<unsigned> ExecutorConcurrency(
+ "execute-concurrency",
+ llvm::cl::desc("The number of threads used to process all files in "
+ "parallel. Set to 0 for hardware concurrency. "
+ "This flag only applies to all-TUs."),
+ llvm::cl::init(0));
+
+class AllTUsToolExecutorPlugin : public ToolExecutorPlugin {
+public:
+ llvm::Expected<std::unique_ptr<ToolExecutor>>
+ create(CommonOptionsParser &OptionsParser) override {
+ if (OptionsParser.getSourcePathList().empty())
+ return make_string_error(
+ "[AllTUsToolExecutorPlugin] Please provide a directory/file path in "
+ "the compilation database.");
+ return llvm::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),
+ ExecutorConcurrency);
+ }
+};
+
+static ToolExecutorPluginRegistry::Add<AllTUsToolExecutorPlugin>
+ X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. "
+ "Tool results are stored in memory.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the plugin.
+volatile int AllTUsToolExecutorAnchorSource = 0;
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp b/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp
new file mode 100644
index 000000000000..f5040b8a09d5
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp
@@ -0,0 +1,134 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains definitions of classes which implement ArgumentsAdjuster
+// interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstddef>
+
+namespace clang {
+namespace tooling {
+
+/// Add -fsyntax-only option to the command line arguments.
+ArgumentsAdjuster getClangSyntaxOnlyAdjuster() {
+ return [](const CommandLineArguments &Args, StringRef /*unused*/) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t i = 0, e = Args.size(); i < e; ++i) {
+ StringRef Arg = Args[i];
+ // FIXME: Remove options that generate output.
+ if (!Arg.startswith("-fcolor-diagnostics") &&
+ !Arg.startswith("-fdiagnostics-color"))
+ AdjustedArgs.push_back(Args[i]);
+ }
+ AdjustedArgs.push_back("-fsyntax-only");
+ return AdjustedArgs;
+ };
+}
+
+ArgumentsAdjuster getClangStripOutputAdjuster() {
+ return [](const CommandLineArguments &Args, StringRef /*unused*/) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t i = 0, e = Args.size(); i < e; ++i) {
+ StringRef Arg = Args[i];
+ if (!Arg.startswith("-o"))
+ AdjustedArgs.push_back(Args[i]);
+
+ if (Arg == "-o") {
+ // Output is specified as -o foo. Skip the next argument too.
+ ++i;
+ }
+ // Else, the output is specified as -ofoo. Just do nothing.
+ }
+ return AdjustedArgs;
+ };
+}
+
+ArgumentsAdjuster getClangStripDependencyFileAdjuster() {
+ return [](const CommandLineArguments &Args, StringRef /*unused*/) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t i = 0, e = Args.size(); i < e; ++i) {
+ StringRef Arg = Args[i];
+ // All dependency-file options begin with -M. These include -MM,
+ // -MF, -MG, -MP, -MT, -MQ, -MD, and -MMD.
+ if (!Arg.startswith("-M")) {
+ AdjustedArgs.push_back(Args[i]);
+ continue;
+ }
+
+ if (Arg == "-MF" || Arg == "-MT" || Arg == "-MQ")
+ // These flags take an argument: -MX foo. Skip the next argument also.
+ ++i;
+ }
+ return AdjustedArgs;
+ };
+}
+
+ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra,
+ ArgumentInsertPosition Pos) {
+ return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) {
+ CommandLineArguments Return(Args);
+
+ CommandLineArguments::iterator I;
+ if (Pos == ArgumentInsertPosition::END) {
+ I = Return.end();
+ } else {
+ I = Return.begin();
+ ++I; // To leave the program name in place
+ }
+
+ Return.insert(I, Extra.begin(), Extra.end());
+ return Return;
+ };
+}
+
+ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra,
+ ArgumentInsertPosition Pos) {
+ return getInsertArgumentAdjuster(CommandLineArguments(1, Extra), Pos);
+}
+
+ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
+ ArgumentsAdjuster Second) {
+ if (!First)
+ return Second;
+ if (!Second)
+ return First;
+ return [First, Second](const CommandLineArguments &Args, StringRef File) {
+ return Second(First(Args, File), File);
+ };
+}
+
+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/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp b/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp
new file mode 100644
index 000000000000..74ad4e83ee3f
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp
@@ -0,0 +1,180 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the CommonOptionsParser class used to parse common
+// command-line options for clang tools, so that they can be run as separate
+// command-line applications with a consistent common interface for handling
+// compilation database and input files.
+//
+// It provides a common subset of command-line options, common algorithm
+// for locating a compilation database and source files, and help messages
+// for the basic command-line interface.
+//
+// It creates a CompilationDatabase and reads common command-line options.
+//
+// This class uses the Clang Tooling infrastructure, see
+// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+// for details on setting it up with LLVM source tree.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace clang::tooling;
+using namespace llvm;
+
+const char *const CommonOptionsParser::HelpMessage =
+ "\n"
+ "-p <build-path> is used to read a compile command database.\n"
+ "\n"
+ "\tFor example, it can be a CMake build directory in which a file named\n"
+ "\tcompile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n"
+ "\tCMake option to get this output). When no build path is specified,\n"
+ "\ta search for compile_commands.json will be attempted through all\n"
+ "\tparent paths of the first input file . See:\n"
+ "\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n"
+ "\texample of setting up Clang Tooling on a source tree.\n"
+ "\n"
+ "<source0> ... specify the paths of source files. These paths are\n"
+ "\tlooked up in the compile command database. If the path of a file is\n"
+ "\tabsolute, it needs to point into CMake's source tree. If the path is\n"
+ "\trelative, the current working directory needs to be in the CMake\n"
+ "\tsource tree and the file must be in a subdirectory of the current\n"
+ "\tworking directory. \"./\" prefixes in the relative files will be\n"
+ "\tautomatically removed, but the rest of a relative path must be a\n"
+ "\tsuffix of a path in the compile command database.\n"
+ "\n";
+
+void ArgumentsAdjustingCompilations::appendArgumentsAdjuster(
+ ArgumentsAdjuster Adjuster) {
+ Adjusters.push_back(std::move(Adjuster));
+}
+
+std::vector<CompileCommand> ArgumentsAdjustingCompilations::getCompileCommands(
+ StringRef FilePath) const {
+ return adjustCommands(Compilations->getCompileCommands(FilePath));
+}
+
+std::vector<std::string>
+ArgumentsAdjustingCompilations::getAllFiles() const {
+ return Compilations->getAllFiles();
+}
+
+std::vector<CompileCommand>
+ArgumentsAdjustingCompilations::getAllCompileCommands() const {
+ return adjustCommands(Compilations->getAllCompileCommands());
+}
+
+std::vector<CompileCommand> ArgumentsAdjustingCompilations::adjustCommands(
+ std::vector<CompileCommand> Commands) const {
+ for (CompileCommand &Command : Commands)
+ for (const auto &Adjuster : Adjusters)
+ Command.CommandLine = Adjuster(Command.CommandLine, Command.Filename);
+ return Commands;
+}
+
+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),
+ cl::sub(*cl::AllSubCommands));
+
+ static cl::list<std::string> SourcePaths(
+ cl::Positional, cl::desc("<source0> [... <sourceN>]"), OccurrencesFlag,
+ cl::cat(Category), cl::sub(*cl::AllSubCommands));
+
+ static cl::list<std::string> ArgsAfter(
+ "extra-arg",
+ cl::desc("Additional argument to append to the compiler command line"),
+ cl::cat(Category), cl::sub(*cl::AllSubCommands));
+
+ static cl::list<std::string> ArgsBefore(
+ "extra-arg-before",
+ cl::desc("Additional argument to prepend to the compiler command line"),
+ cl::cat(Category), cl::sub(*cl::AllSubCommands));
+
+ cl::ResetAllOptionOccurrences();
+
+ cl::HideUnrelatedOptions(Category);
+
+ std::string ErrorMessage;
+ Compilations =
+ FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage);
+ if (!ErrorMessage.empty())
+ ErrorMessage.append("\n");
+ llvm::raw_string_ostream OS(ErrorMessage);
+ // Stop initializing if command-line option parsing failed.
+ if (!cl::ParseCommandLineOptions(argc, argv, Overview, &OS)) {
+ OS.flush();
+ return llvm::make_error<llvm::StringError>("[CommonOptionsParser]: " +
+ ErrorMessage,
+ llvm::inconvertibleErrorCode());
+ }
+
+ cl::PrintOptionValues();
+
+ SourcePathList = SourcePaths;
+ if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) &&
+ SourcePathList.empty())
+ return llvm::Error::success();
+ if (!Compilations) {
+ if (!BuildPath.empty()) {
+ Compilations =
+ CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage);
+ } else {
+ Compilations = CompilationDatabase::autoDetectFromSource(SourcePaths[0],
+ ErrorMessage);
+ }
+ if (!Compilations) {
+ llvm::errs() << "Error while trying to load a compilation database:\n"
+ << ErrorMessage << "Running without flags.\n";
+ Compilations.reset(
+ new FixedCompilationDatabase(".", std::vector<std::string>()));
+ }
+ }
+ auto AdjustingCompilations =
+ llvm::make_unique<ArgumentsAdjustingCompilations>(
+ std::move(Compilations));
+ Adjuster =
+ getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN);
+ Adjuster = combineAdjusters(
+ std::move(Adjuster),
+ getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END));
+ AdjustingCompilations->appendArgumentsAdjuster(Adjuster);
+ Compilations = std::move(AdjustingCompilations);
+ return llvm::Error::success();
+}
+
+llvm::Expected<CommonOptionsParser> CommonOptionsParser::create(
+ int &argc, const char **argv, llvm::cl::OptionCategory &Category,
+ llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
+ CommonOptionsParser Parser;
+ llvm::Error Err =
+ Parser.init(argc, argv, Category, OccurrencesFlag, Overview);
+ if (Err)
+ return std::move(Err);
+ return std::move(Parser);
+}
+
+CommonOptionsParser::CommonOptionsParser(
+ int &argc, const char **argv, cl::OptionCategory &Category,
+ llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
+ llvm::Error Err = init(argc, argv, Category, OccurrencesFlag, Overview);
+ if (Err) {
+ llvm::report_fatal_error(
+ "CommonOptionsParser: failed to parse command-line arguments. " +
+ llvm::toString(std::move(Err)));
+ }
+}
diff --git a/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp b/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp
new file mode 100644
index 000000000000..cce8e1f1df24
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp
@@ -0,0 +1,421 @@
+//===- CompilationDatabase.cpp --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains implementations of the CompilationDatabase base class
+// and the FixedCompilationDatabase.
+//
+// FIXME: Various functions that take a string &ErrorMessage should be upgraded
+// to Expected.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Driver/Action.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Job.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <iterator>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <system_error>
+#include <utility>
+#include <vector>
+
+using namespace clang;
+using namespace tooling;
+
+LLVM_INSTANTIATE_REGISTRY(CompilationDatabasePluginRegistry)
+
+CompilationDatabase::~CompilationDatabase() = default;
+
+std::unique_ptr<CompilationDatabase>
+CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
+ std::string &ErrorMessage) {
+ llvm::raw_string_ostream ErrorStream(ErrorMessage);
+ for (CompilationDatabasePluginRegistry::iterator
+ It = CompilationDatabasePluginRegistry::begin(),
+ Ie = CompilationDatabasePluginRegistry::end();
+ It != Ie; ++It) {
+ std::string DatabaseErrorMessage;
+ std::unique_ptr<CompilationDatabasePlugin> Plugin(It->instantiate());
+ if (std::unique_ptr<CompilationDatabase> DB =
+ Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
+ return DB;
+ ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
+ }
+ return nullptr;
+}
+
+static std::unique_ptr<CompilationDatabase>
+findCompilationDatabaseFromDirectory(StringRef Directory,
+ std::string &ErrorMessage) {
+ std::stringstream ErrorStream;
+ bool HasErrorMessage = false;
+ while (!Directory.empty()) {
+ std::string LoadErrorMessage;
+
+ if (std::unique_ptr<CompilationDatabase> DB =
+ CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
+ return DB;
+
+ if (!HasErrorMessage) {
+ ErrorStream << "No compilation database found in " << Directory.str()
+ << " or any parent directory\n" << LoadErrorMessage;
+ HasErrorMessage = true;
+ }
+
+ Directory = llvm::sys::path::parent_path(Directory);
+ }
+ ErrorMessage = ErrorStream.str();
+ return nullptr;
+}
+
+std::unique_ptr<CompilationDatabase>
+CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
+ std::string &ErrorMessage) {
+ SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
+ StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
+
+ std::unique_ptr<CompilationDatabase> DB =
+ findCompilationDatabaseFromDirectory(Directory, ErrorMessage);
+
+ if (!DB)
+ ErrorMessage = ("Could not auto-detect compilation database for file \"" +
+ SourceFile + "\"\n" + ErrorMessage).str();
+ return DB;
+}
+
+std::unique_ptr<CompilationDatabase>
+CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
+ std::string &ErrorMessage) {
+ SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
+
+ std::unique_ptr<CompilationDatabase> DB =
+ findCompilationDatabaseFromDirectory(AbsolutePath, ErrorMessage);
+
+ if (!DB)
+ ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
+ SourceDir + "\"\n" + ErrorMessage).str();
+ return DB;
+}
+
+std::vector<CompileCommand> CompilationDatabase::getAllCompileCommands() const {
+ std::vector<CompileCommand> Result;
+ for (const auto &File : getAllFiles()) {
+ auto C = getCompileCommands(File);
+ std::move(C.begin(), C.end(), std::back_inserter(Result));
+ }
+ return Result;
+}
+
+CompilationDatabasePlugin::~CompilationDatabasePlugin() = default;
+
+namespace {
+
+// Helper for recursively searching through a chain of actions and collecting
+// all inputs, direct and indirect, of compile jobs.
+struct CompileJobAnalyzer {
+ SmallVector<std::string, 2> Inputs;
+
+ void run(const driver::Action *A) {
+ runImpl(A, false);
+ }
+
+private:
+ void runImpl(const driver::Action *A, bool Collect) {
+ bool CollectChildren = Collect;
+ switch (A->getKind()) {
+ case driver::Action::CompileJobClass:
+ CollectChildren = true;
+ break;
+
+ case driver::Action::InputClass:
+ if (Collect) {
+ const auto *IA = cast<driver::InputAction>(A);
+ Inputs.push_back(IA->getInputArg().getSpelling());
+ }
+ break;
+
+ default:
+ // Don't care about others
+ break;
+ }
+
+ for (const driver::Action *AI : A->inputs())
+ runImpl(AI, CollectChildren);
+ }
+};
+
+// Special DiagnosticConsumer that looks for warn_drv_input_file_unused
+// diagnostics from the driver and collects the option strings for those unused
+// options.
+class UnusedInputDiagConsumer : public DiagnosticConsumer {
+public:
+ UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {}
+
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) override {
+ if (Info.getID() == diag::warn_drv_input_file_unused) {
+ // Arg 1 for this diagnostic is the option that didn't get used.
+ UnusedInputs.push_back(Info.getArgStdStr(0));
+ } else if (DiagLevel >= DiagnosticsEngine::Error) {
+ // If driver failed to create compilation object, show the diagnostics
+ // to user.
+ Other.HandleDiagnostic(DiagLevel, Info);
+ }
+ }
+
+ DiagnosticConsumer &Other;
+ SmallVector<std::string, 2> UnusedInputs;
+};
+
+// Unary functor for asking "Given a StringRef S1, does there exist a string
+// S2 in Arr where S1 == S2?"
+struct MatchesAny {
+ MatchesAny(ArrayRef<std::string> Arr) : Arr(Arr) {}
+
+ bool operator() (StringRef S) {
+ for (const std::string *I = Arr.begin(), *E = Arr.end(); I != E; ++I)
+ if (*I == S)
+ return true;
+ return false;
+ }
+
+private:
+ ArrayRef<std::string> Arr;
+};
+
+// Filter of tools unused flags such as -no-integrated-as and -Wa,*.
+// They are not used for syntax checking, and could confuse targets
+// which don't support these options.
+struct FilterUnusedFlags {
+ bool operator() (StringRef S) {
+ return (S == "-no-integrated-as") || S.startswith("-Wa,");
+ }
+};
+
+std::string GetClangToolCommand() {
+ static int Dummy;
+ std::string ClangExecutable =
+ llvm::sys::fs::getMainExecutable("clang", (void *)&Dummy);
+ SmallString<128> ClangToolPath;
+ ClangToolPath = llvm::sys::path::parent_path(ClangExecutable);
+ llvm::sys::path::append(ClangToolPath, "clang-tool");
+ return ClangToolPath.str();
+}
+
+} // namespace
+
+/// Strips any positional args and possible argv[0] from a command-line
+/// provided by the user to construct a FixedCompilationDatabase.
+///
+/// FixedCompilationDatabase requires a command line to be in this format as it
+/// constructs the command line for each file by appending the name of the file
+/// to be compiled. FixedCompilationDatabase also adds its own argv[0] to the
+/// start of the command line although its value is not important as it's just
+/// ignored by the Driver invoked by the ClangTool using the
+/// FixedCompilationDatabase.
+///
+/// FIXME: This functionality should probably be made available by
+/// clang::driver::Driver although what the interface should look like is not
+/// clear.
+///
+/// \param[in] Args Args as provided by the user.
+/// \return Resulting stripped command line.
+/// \li true if successful.
+/// \li false if \c Args cannot be used for compilation jobs (e.g.
+/// contains an option like -E or -version).
+static bool stripPositionalArgs(std::vector<const char *> Args,
+ std::vector<std::string> &Result,
+ std::string &ErrorMsg) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ llvm::raw_string_ostream Output(ErrorMsg);
+ TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
+ UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
+ &*DiagOpts, &DiagClient, false);
+
+ // The clang executable path isn't required since the jobs the driver builds
+ // will not be executed.
+ std::unique_ptr<driver::Driver> NewDriver(new driver::Driver(
+ /* ClangExecutable= */ "", llvm::sys::getDefaultTargetTriple(),
+ Diagnostics));
+ NewDriver->setCheckInputsExist(false);
+
+ // This becomes the new argv[0]. The value is used to detect libc++ include
+ // dirs on Mac, it isn't used for other platforms.
+ std::string Argv0 = GetClangToolCommand();
+ Args.insert(Args.begin(), Argv0.c_str());
+
+ // By adding -c, we force the driver to treat compilation as the last phase.
+ // It will then issue warnings via Diagnostics about un-used options that
+ // would have been used for linking. If the user provided a compiler name as
+ // the original argv[0], this will be treated as a linker input thanks to
+ // insertng a new argv[0] above. All un-used options get collected by
+ // UnusedInputdiagConsumer and get stripped out later.
+ Args.push_back("-c");
+
+ // Put a dummy C++ file on to ensure there's at least one compile job for the
+ // driver to construct. If the user specified some other argument that
+ // prevents compilation, e.g. -E or something like -version, we may still end
+ // up with no jobs but then this is the user's fault.
+ Args.push_back("placeholder.cpp");
+
+ Args.erase(std::remove_if(Args.begin(), Args.end(), FilterUnusedFlags()),
+ Args.end());
+
+ const std::unique_ptr<driver::Compilation> Compilation(
+ NewDriver->BuildCompilation(Args));
+ if (!Compilation)
+ return false;
+
+ const driver::JobList &Jobs = Compilation->getJobs();
+
+ CompileJobAnalyzer CompileAnalyzer;
+
+ for (const auto &Cmd : Jobs) {
+ // Collect only for Assemble, Backend, and Compile jobs. If we do all jobs
+ // we get duplicates since Link jobs point to Assemble jobs as inputs.
+ // -flto* flags make the BackendJobClass, which still needs analyzer.
+ if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass ||
+ Cmd.getSource().getKind() == driver::Action::BackendJobClass ||
+ Cmd.getSource().getKind() == driver::Action::CompileJobClass) {
+ CompileAnalyzer.run(&Cmd.getSource());
+ }
+ }
+
+ if (CompileAnalyzer.Inputs.empty()) {
+ ErrorMsg = "warning: no compile jobs found\n";
+ return false;
+ }
+
+ // Remove all compilation input files from the command line. This is
+ // necessary so that getCompileCommands() can construct a command line for
+ // each file.
+ std::vector<const char *>::iterator End = std::remove_if(
+ Args.begin(), Args.end(), MatchesAny(CompileAnalyzer.Inputs));
+
+ // Remove all inputs deemed unused for compilation.
+ End = std::remove_if(Args.begin(), End, MatchesAny(DiagClient.UnusedInputs));
+
+ // Remove the -c add above as well. It will be at the end right now.
+ assert(strcmp(*(End - 1), "-c") == 0);
+ --End;
+
+ Result = std::vector<std::string>(Args.begin() + 1, End);
+ return true;
+}
+
+std::unique_ptr<FixedCompilationDatabase>
+FixedCompilationDatabase::loadFromCommandLine(int &Argc,
+ const char *const *Argv,
+ std::string &ErrorMsg,
+ Twine Directory) {
+ ErrorMsg.clear();
+ if (Argc == 0)
+ return nullptr;
+ const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
+ if (DoubleDash == Argv + Argc)
+ return nullptr;
+ std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc);
+ Argc = DoubleDash - Argv;
+
+ std::vector<std::string> StrippedArgs;
+ if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg))
+ return nullptr;
+ return llvm::make_unique<FixedCompilationDatabase>(Directory, StrippedArgs);
+}
+
+std::unique_ptr<FixedCompilationDatabase>
+FixedCompilationDatabase::loadFromFile(StringRef Path, std::string &ErrorMsg) {
+ ErrorMsg.clear();
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+ llvm::MemoryBuffer::getFile(Path);
+ if (std::error_code Result = File.getError()) {
+ ErrorMsg = "Error while opening fixed database: " + Result.message();
+ return nullptr;
+ }
+ std::vector<std::string> Args{llvm::line_iterator(**File),
+ llvm::line_iterator()};
+ return llvm::make_unique<FixedCompilationDatabase>(
+ llvm::sys::path::parent_path(Path), std::move(Args));
+}
+
+FixedCompilationDatabase::
+FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) {
+ std::vector<std::string> ToolCommandLine(1, GetClangToolCommand());
+ ToolCommandLine.insert(ToolCommandLine.end(),
+ CommandLine.begin(), CommandLine.end());
+ CompileCommands.emplace_back(Directory, StringRef(),
+ std::move(ToolCommandLine),
+ StringRef());
+}
+
+std::vector<CompileCommand>
+FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
+ std::vector<CompileCommand> Result(CompileCommands);
+ Result[0].CommandLine.push_back(FilePath);
+ Result[0].Filename = FilePath;
+ return Result;
+}
+
+namespace {
+
+class FixedCompilationDatabasePlugin : public CompilationDatabasePlugin {
+ std::unique_ptr<CompilationDatabase>
+ loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
+ SmallString<1024> DatabasePath(Directory);
+ llvm::sys::path::append(DatabasePath, "compile_flags.txt");
+ return FixedCompilationDatabase::loadFromFile(DatabasePath, ErrorMessage);
+ }
+};
+
+} // namespace
+
+static CompilationDatabasePluginRegistry::Add<FixedCompilationDatabasePlugin>
+X("fixed-compilation-database", "Reads plain-text flags file");
+
+namespace clang {
+namespace tooling {
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the JSONCompilationDatabasePlugin.
+extern volatile int JSONAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED JSONAnchorDest = JSONAnchorSource;
+
+} // namespace tooling
+} // namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp
new file mode 100644
index 000000000000..e3a33d9a3755
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp
@@ -0,0 +1,51 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements classes to support/store diagnostics refactoring.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Core/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+
+namespace clang {
+namespace tooling {
+
+DiagnosticMessage::DiagnosticMessage(llvm::StringRef Message)
+ : Message(Message), FileOffset(0) {}
+
+DiagnosticMessage::DiagnosticMessage(llvm::StringRef Message,
+ const SourceManager &Sources,
+ SourceLocation Loc)
+ : Message(Message), FileOffset(0) {
+ assert(Loc.isValid() && Loc.isFileID());
+ FilePath = Sources.getFilename(Loc);
+
+ // Don't store offset in the scratch space. It doesn't tell anything to the
+ // user. Moreover, it depends on the history of macro expansions and thus
+ // prevents deduplication of warnings in headers.
+ if (!FilePath.empty())
+ FileOffset = Sources.getFileOffset(Loc);
+}
+
+Diagnostic::Diagnostic(llvm::StringRef DiagnosticName,
+ Diagnostic::Level DiagLevel, StringRef BuildDirectory)
+ : DiagnosticName(DiagnosticName), DiagLevel(DiagLevel),
+ BuildDirectory(BuildDirectory) {}
+
+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),
+ DiagLevel(DiagLevel), BuildDirectory(BuildDirectory) {}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Core/Lookup.cpp b/contrib/llvm/tools/clang/lib/Tooling/Core/Lookup.cpp
new file mode 100644
index 000000000000..cc448d144e2c
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Core/Lookup.cpp
@@ -0,0 +1,191 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines helper methods for clang tools performing name lookup.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Core/Lookup.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclarationName.h"
+using namespace clang;
+using namespace clang::tooling;
+
+// Gets all namespaces that \p Context is in as a vector (ignoring anonymous
+// namespaces). The inner namespaces come before outer namespaces in the vector.
+// For example, if the context is in the following namespace:
+// `namespace a { namespace b { namespace c ( ... ) } }`,
+// the vector will be `{c, b, a}`.
+static llvm::SmallVector<const NamespaceDecl *, 4>
+getAllNamedNamespaces(const DeclContext *Context) {
+ llvm::SmallVector<const NamespaceDecl *, 4> Namespaces;
+ auto GetNextNamedNamespace = [](const DeclContext *Context) {
+ // Look past non-namespaces and anonymous namespaces on FromContext.
+ while (Context && (!isa<NamespaceDecl>(Context) ||
+ cast<NamespaceDecl>(Context)->isAnonymousNamespace()))
+ Context = Context->getParent();
+ return Context;
+ };
+ for (Context = GetNextNamedNamespace(Context); Context != nullptr;
+ Context = GetNextNamedNamespace(Context->getParent()))
+ Namespaces.push_back(cast<NamespaceDecl>(Context));
+ return Namespaces;
+}
+
+// Returns true if the context in which the type is used and the context in
+// which the type is declared are the same semantical namespace but different
+// lexical namespaces.
+static bool
+usingFromDifferentCanonicalNamespace(const DeclContext *FromContext,
+ const DeclContext *UseContext) {
+ // We can skip anonymous namespace because:
+ // 1. `FromContext` and `UseContext` must be in the same anonymous namespaces
+ // since referencing across anonymous namespaces is not possible.
+ // 2. If `FromContext` and `UseContext` are in the same anonymous namespace,
+ // the function will still return `false` as expected.
+ llvm::SmallVector<const NamespaceDecl *, 4> FromNamespaces =
+ getAllNamedNamespaces(FromContext);
+ llvm::SmallVector<const NamespaceDecl *, 4> UseNamespaces =
+ getAllNamedNamespaces(UseContext);
+ // If `UseContext` has fewer level of nested namespaces, it cannot be in the
+ // same canonical namespace as the `FromContext`.
+ if (UseNamespaces.size() < FromNamespaces.size())
+ return false;
+ unsigned Diff = UseNamespaces.size() - FromNamespaces.size();
+ auto FromIter = FromNamespaces.begin();
+ // Only compare `FromNamespaces` with namespaces in `UseNamespaces` that can
+ // collide, i.e. the top N namespaces where N is the number of namespaces in
+ // `FromNamespaces`.
+ auto UseIter = UseNamespaces.begin() + Diff;
+ for (; FromIter != FromNamespaces.end() && UseIter != UseNamespaces.end();
+ ++FromIter, ++UseIter) {
+ // Literally the same namespace, not a collision.
+ if (*FromIter == *UseIter)
+ return false;
+ // Now check the names. If they match we have a different canonical
+ // namespace with the same name.
+ if (cast<NamespaceDecl>(*FromIter)->getDeclName() ==
+ cast<NamespaceDecl>(*UseIter)->getDeclName())
+ return true;
+ }
+ assert(FromIter == FromNamespaces.end() && UseIter == UseNamespaces.end());
+ return false;
+}
+
+static StringRef getBestNamespaceSubstr(const DeclContext *DeclA,
+ StringRef NewName,
+ bool HadLeadingColonColon) {
+ while (true) {
+ while (DeclA && !isa<NamespaceDecl>(DeclA))
+ DeclA = DeclA->getParent();
+
+ // Fully qualified it is! Leave :: in place if it's there already.
+ if (!DeclA)
+ return HadLeadingColonColon ? NewName : NewName.substr(2);
+
+ // Otherwise strip off redundant namespace qualifications from the new name.
+ // We use the fully qualified name of the namespace and remove that part
+ // from NewName if it has an identical prefix.
+ std::string NS =
+ "::" + cast<NamespaceDecl>(DeclA)->getQualifiedNameAsString() + "::";
+ if (NewName.startswith(NS))
+ return NewName.substr(NS.size());
+
+ // No match yet. Strip of a namespace from the end of the chain and try
+ // again. This allows to get optimal qualifications even if the old and new
+ // decl only share common namespaces at a higher level.
+ DeclA = DeclA->getParent();
+ }
+}
+
+/// Check if the name specifier begins with a written "::".
+static bool isFullyQualified(const NestedNameSpecifier *NNS) {
+ while (NNS) {
+ if (NNS->getKind() == NestedNameSpecifier::Global)
+ return true;
+ NNS = NNS->getPrefix();
+ }
+ 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.
+// FIXME: consider using namespaces.
+static bool isAmbiguousNameInScope(StringRef Spelling, StringRef QName,
+ const DeclContext &UseContext) {
+ assert(QName.startswith("::"));
+ if (Spelling.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 = Spelling.split("::").first;
+
+ llvm::SmallVector<const NamespaceDecl *, 4> UseNamespaces =
+ 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;
+ }
+ }
+ return false;
+}
+
+std::string tooling::replaceNestedName(const NestedNameSpecifier *Use,
+ const DeclContext *UseContext,
+ const NamedDecl *FromDecl,
+ StringRef ReplacementString) {
+ assert(ReplacementString.startswith("::") &&
+ "Expected fully-qualified name!");
+
+ // We can do a raw name replacement when we are not inside the namespace for
+ // the original class/function and it is not in the global namespace. The
+ // assumption is that outside the original namespace we must have a using
+ // statement that makes this work out and that other parts of this refactor
+ // will automatically fix using statements to point to the new class/function.
+ // However, if the `FromDecl` is a class forward declaration, the reference is
+ // still considered as referring to the original definition, so we can't do a
+ // raw name replacement in this case.
+ const bool class_name_only = !Use;
+ const bool in_global_namespace =
+ isa<TranslationUnitDecl>(FromDecl->getDeclContext());
+ const bool is_class_forward_decl =
+ isa<CXXRecordDecl>(FromDecl) &&
+ !cast<CXXRecordDecl>(FromDecl)->isCompleteDefinition();
+ if (class_name_only && !in_global_namespace && !is_class_forward_decl &&
+ !usingFromDifferentCanonicalNamespace(FromDecl->getDeclContext(),
+ UseContext)) {
+ auto Pos = ReplacementString.rfind("::");
+ return Pos != StringRef::npos ? ReplacementString.substr(Pos + 2)
+ : ReplacementString;
+ }
+ // We did not match this because of a using statement, so we will need to
+ // figure out how good a namespace match we have with our destination type.
+ // We work backwards (from most specific possible namespace to least
+ // 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;
+}
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Core/Replacement.cpp b/contrib/llvm/tools/clang/lib/Tooling/Core/Replacement.cpp
new file mode 100644
index 000000000000..3b7e39814afa
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Core/Replacement.cpp
@@ -0,0 +1,628 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements classes to support/store refactorings.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Rewrite/Core/RewriteBuffer.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <limits>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace clang;
+using namespace tooling;
+
+static const char * const InvalidLocation = "";
+
+Replacement::Replacement() : FilePath(InvalidLocation) {}
+
+Replacement::Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
+ StringRef ReplacementText)
+ : FilePath(FilePath), ReplacementRange(Offset, Length),
+ ReplacementText(ReplacementText) {}
+
+Replacement::Replacement(const SourceManager &Sources, SourceLocation Start,
+ unsigned Length, StringRef ReplacementText) {
+ setFromSourceLocation(Sources, Start, Length, ReplacementText);
+}
+
+Replacement::Replacement(const SourceManager &Sources,
+ const CharSourceRange &Range,
+ StringRef ReplacementText,
+ const LangOptions &LangOpts) {
+ setFromSourceRange(Sources, Range, ReplacementText, LangOpts);
+}
+
+bool Replacement::isApplicable() const {
+ return FilePath != InvalidLocation;
+}
+
+bool Replacement::apply(Rewriter &Rewrite) const {
+ SourceManager &SM = Rewrite.getSourceMgr();
+ const FileEntry *Entry = SM.getFileManager().getFile(FilePath);
+ if (!Entry)
+ return false;
+
+ FileID ID = SM.getOrCreateFileID(Entry, SrcMgr::C_User);
+ const SourceLocation Start =
+ SM.getLocForStartOfFile(ID).
+ getLocWithOffset(ReplacementRange.getOffset());
+ // ReplaceText returns false on success.
+ // ReplaceText only fails if the source location is not a file location, in
+ // which case we already returned false earlier.
+ bool RewriteSucceeded = !Rewrite.ReplaceText(
+ Start, ReplacementRange.getLength(), ReplacementText);
+ assert(RewriteSucceeded);
+ return RewriteSucceeded;
+}
+
+std::string Replacement::toString() const {
+ std::string Result;
+ llvm::raw_string_ostream Stream(Result);
+ Stream << FilePath << ": " << ReplacementRange.getOffset() << ":+"
+ << ReplacementRange.getLength() << ":\"" << ReplacementText << "\"";
+ return Stream.str();
+}
+
+namespace clang {
+namespace tooling {
+
+bool operator<(const Replacement &LHS, const Replacement &RHS) {
+ if (LHS.getOffset() != RHS.getOffset())
+ return LHS.getOffset() < RHS.getOffset();
+
+ if (LHS.getLength() != RHS.getLength())
+ return LHS.getLength() < RHS.getLength();
+
+ if (LHS.getFilePath() != RHS.getFilePath())
+ return LHS.getFilePath() < RHS.getFilePath();
+ return LHS.getReplacementText() < RHS.getReplacementText();
+}
+
+bool operator==(const Replacement &LHS, const Replacement &RHS) {
+ return LHS.getOffset() == RHS.getOffset() &&
+ LHS.getLength() == RHS.getLength() &&
+ LHS.getFilePath() == RHS.getFilePath() &&
+ LHS.getReplacementText() == RHS.getReplacementText();
+}
+
+} // namespace tooling
+} // namespace clang
+
+void Replacement::setFromSourceLocation(const SourceManager &Sources,
+ SourceLocation Start, unsigned Length,
+ StringRef ReplacementText) {
+ const std::pair<FileID, unsigned> DecomposedLocation =
+ Sources.getDecomposedLoc(Start);
+ const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
+ this->FilePath = Entry ? Entry->getName() : InvalidLocation;
+ this->ReplacementRange = Range(DecomposedLocation.second, Length);
+ this->ReplacementText = ReplacementText;
+}
+
+// FIXME: This should go into the Lexer, but we need to figure out how
+// to handle ranges for refactoring in general first - there is no obvious
+// good way how to integrate this into the Lexer yet.
+static int getRangeSize(const SourceManager &Sources,
+ const CharSourceRange &Range,
+ const LangOptions &LangOpts) {
+ SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin());
+ SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd());
+ std::pair<FileID, unsigned> Start = Sources.getDecomposedLoc(SpellingBegin);
+ std::pair<FileID, unsigned> End = Sources.getDecomposedLoc(SpellingEnd);
+ if (Start.first != End.first) return -1;
+ if (Range.isTokenRange())
+ End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources, LangOpts);
+ return End.second - Start.second;
+}
+
+void Replacement::setFromSourceRange(const SourceManager &Sources,
+ const CharSourceRange &Range,
+ StringRef ReplacementText,
+ const LangOptions &LangOpts) {
+ setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
+ getRangeSize(Sources, Range, LangOpts),
+ ReplacementText);
+}
+
+Replacement
+Replacements::getReplacementInChangedCode(const Replacement &R) const {
+ unsigned NewStart = getShiftedCodePosition(R.getOffset());
+ unsigned NewEnd = getShiftedCodePosition(R.getOffset() + R.getLength());
+ return Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
+ R.getReplacementText());
+}
+
+static std::string getReplacementErrString(replacement_error Err) {
+ switch (Err) {
+ case replacement_error::fail_to_apply:
+ return "Failed to apply a replacement.";
+ case replacement_error::wrong_file_path:
+ return "The new replacement's file path is different from the file path of "
+ "existing replacements";
+ case replacement_error::overlap_conflict:
+ return "The new replacement overlaps with an existing replacement.";
+ case replacement_error::insert_conflict:
+ return "The new insertion has the same insert location as an existing "
+ "replacement.";
+ }
+ llvm_unreachable("A value of replacement_error has no message.");
+}
+
+std::string ReplacementError::message() const {
+ std::string Message = getReplacementErrString(Err);
+ if (NewReplacement.hasValue())
+ Message += "\nNew replacement: " + NewReplacement->toString();
+ if (ExistingReplacement.hasValue())
+ Message += "\nExisting replacement: " + ExistingReplacement->toString();
+ return Message;
+}
+
+char ReplacementError::ID = 0;
+
+Replacements Replacements::getCanonicalReplacements() const {
+ std::vector<Replacement> NewReplaces;
+ // Merge adjacent replacements.
+ for (const auto &R : Replaces) {
+ if (NewReplaces.empty()) {
+ NewReplaces.push_back(R);
+ continue;
+ }
+ auto &Prev = NewReplaces.back();
+ unsigned PrevEnd = Prev.getOffset() + Prev.getLength();
+ if (PrevEnd < R.getOffset()) {
+ NewReplaces.push_back(R);
+ } else {
+ assert(PrevEnd == R.getOffset() &&
+ "Existing replacements must not overlap.");
+ Replacement NewR(
+ R.getFilePath(), Prev.getOffset(), Prev.getLength() + R.getLength(),
+ (Prev.getReplacementText() + R.getReplacementText()).str());
+ Prev = NewR;
+ }
+ }
+ ReplacementsImpl NewReplacesImpl(NewReplaces.begin(), NewReplaces.end());
+ return Replacements(NewReplacesImpl.begin(), NewReplacesImpl.end());
+}
+
+// `R` and `Replaces` are order-independent if applying them in either order
+// has the same effect, so we need to compare replacements associated to
+// applying them in either order.
+llvm::Expected<Replacements>
+Replacements::mergeIfOrderIndependent(const Replacement &R) const {
+ Replacements Rs(R);
+ // A Replacements set containing a single replacement that is `R` referring to
+ // the code after the existing replacements `Replaces` are applied.
+ Replacements RsShiftedByReplaces(getReplacementInChangedCode(R));
+ // A Replacements set that is `Replaces` referring to the code after `R` is
+ // applied.
+ Replacements ReplacesShiftedByRs;
+ for (const auto &Replace : Replaces)
+ ReplacesShiftedByRs.Replaces.insert(
+ Rs.getReplacementInChangedCode(Replace));
+ // This is equivalent to applying `Replaces` first and then `R`.
+ auto MergeShiftedRs = merge(RsShiftedByReplaces);
+ // This is equivalent to applying `R` first and then `Replaces`.
+ auto MergeShiftedReplaces = Rs.merge(ReplacesShiftedByRs);
+
+ // Since empty or segmented replacements around existing replacements might be
+ // produced above, we need to compare replacements in canonical forms.
+ if (MergeShiftedRs.getCanonicalReplacements() ==
+ MergeShiftedReplaces.getCanonicalReplacements())
+ return MergeShiftedRs;
+ return llvm::make_error<ReplacementError>(replacement_error::overlap_conflict,
+ R, *Replaces.begin());
+}
+
+llvm::Error Replacements::add(const Replacement &R) {
+ // Check the file path.
+ if (!Replaces.empty() && R.getFilePath() != Replaces.begin()->getFilePath())
+ return llvm::make_error<ReplacementError>(
+ replacement_error::wrong_file_path, R, *Replaces.begin());
+
+ // Special-case header insertions.
+ if (R.getOffset() == std::numeric_limits<unsigned>::max()) {
+ Replaces.insert(R);
+ return llvm::Error::success();
+ }
+
+ // This replacement cannot conflict with replacements that end before
+ // this replacement starts or start after this replacement ends.
+ // We also know that there currently are no overlapping replacements.
+ // Thus, we know that all replacements that start after the end of the current
+ // replacement cannot overlap.
+ Replacement AtEnd(R.getFilePath(), R.getOffset() + R.getLength(), 0, "");
+
+ // Find the first entry that starts after or at the end of R. Note that
+ // entries that start at the end can still be conflicting if R is an
+ // insertion.
+ auto I = Replaces.lower_bound(AtEnd);
+ // If `I` starts at the same offset as `R`, `R` must be an insertion.
+ if (I != Replaces.end() && R.getOffset() == I->getOffset()) {
+ assert(R.getLength() == 0);
+ // `I` is also an insertion, `R` and `I` conflict.
+ if (I->getLength() == 0) {
+ // Check if two insertions are order-indepedent: if inserting them in
+ // either order produces the same text, they are order-independent.
+ if ((R.getReplacementText() + I->getReplacementText()).str() !=
+ (I->getReplacementText() + R.getReplacementText()).str())
+ return llvm::make_error<ReplacementError>(
+ replacement_error::insert_conflict, R, *I);
+ // If insertions are order-independent, we can merge them.
+ Replacement NewR(
+ R.getFilePath(), R.getOffset(), 0,
+ (R.getReplacementText() + I->getReplacementText()).str());
+ Replaces.erase(I);
+ Replaces.insert(std::move(NewR));
+ return llvm::Error::success();
+ }
+ // Insertion `R` is adjacent to a non-insertion replacement `I`, so they
+ // are order-independent. It is safe to assume that `R` will not conflict
+ // with any replacement before `I` since all replacements before `I` must
+ // either end before `R` or end at `R` but has length > 0 (if the
+ // replacement before `I` is an insertion at `R`, it would have been `I`
+ // since it is a lower bound of `AtEnd` and ordered before the current `I`
+ // in the set).
+ Replaces.insert(R);
+ return llvm::Error::success();
+ }
+
+ // `I` is the smallest iterator (after `R`) whose entry cannot overlap.
+ // If that is begin(), there are no overlaps.
+ if (I == Replaces.begin()) {
+ Replaces.insert(R);
+ return llvm::Error::success();
+ }
+ --I;
+ auto Overlap = [](const Replacement &R1, const Replacement &R2) -> bool {
+ return Range(R1.getOffset(), R1.getLength())
+ .overlapsWith(Range(R2.getOffset(), R2.getLength()));
+ };
+ // If the previous entry does not overlap, we know that entries before it
+ // can also not overlap.
+ if (!Overlap(R, *I)) {
+ // If `R` and `I` do not have the same offset, it is safe to add `R` since
+ // it must come after `I`. Otherwise:
+ // - If `R` is an insertion, `I` must not be an insertion since it would
+ // have come after `AtEnd`.
+ // - If `R` is not an insertion, `I` must be an insertion; otherwise, `R`
+ // and `I` would have overlapped.
+ // In either case, we can safely insert `R`.
+ Replaces.insert(R);
+ } else {
+ // `I` overlaps with `R`. We need to check `R` against all overlapping
+ // replacements to see if they are order-indepedent. If they are, merge `R`
+ // with them and replace them with the merged replacements.
+ auto MergeBegin = I;
+ auto MergeEnd = std::next(I);
+ while (I != Replaces.begin()) {
+ --I;
+ // If `I` doesn't overlap with `R`, don't merge it.
+ if (!Overlap(R, *I))
+ break;
+ MergeBegin = I;
+ }
+ Replacements OverlapReplaces(MergeBegin, MergeEnd);
+ llvm::Expected<Replacements> Merged =
+ OverlapReplaces.mergeIfOrderIndependent(R);
+ if (!Merged)
+ return Merged.takeError();
+ Replaces.erase(MergeBegin, MergeEnd);
+ Replaces.insert(Merged->begin(), Merged->end());
+ }
+ return llvm::Error::success();
+}
+
+namespace {
+
+// Represents a merged replacement, i.e. a replacement consisting of multiple
+// overlapping replacements from 'First' and 'Second' in mergeReplacements.
+//
+// Position projection:
+// Offsets and lengths of the replacements can generally refer to two different
+// coordinate spaces. Replacements from 'First' refer to the original text
+// whereas replacements from 'Second' refer to the text after applying 'First'.
+//
+// MergedReplacement always operates in the coordinate space of the original
+// text, i.e. transforms elements from 'Second' to take into account what was
+// changed based on the elements from 'First'.
+//
+// We can correctly calculate this projection as we look at the replacements in
+// order of strictly increasing offsets.
+//
+// Invariants:
+// * We always merge elements from 'First' into elements from 'Second' and vice
+// versa. Within each set, the replacements are non-overlapping.
+// * We only extend to the right, i.e. merge elements with strictly increasing
+// offsets.
+class MergedReplacement {
+public:
+ MergedReplacement(const Replacement &R, bool MergeSecond, int D)
+ : MergeSecond(MergeSecond), Delta(D), FilePath(R.getFilePath()),
+ Offset(R.getOffset() + (MergeSecond ? 0 : Delta)), Length(R.getLength()),
+ Text(R.getReplacementText()) {
+ Delta += MergeSecond ? 0 : Text.size() - Length;
+ DeltaFirst = MergeSecond ? Text.size() - Length : 0;
+ }
+
+ // Merges the next element 'R' into this merged element. As we always merge
+ // from 'First' into 'Second' or vice versa, the MergedReplacement knows what
+ // set the next element is coming from.
+ void merge(const Replacement &R) {
+ if (MergeSecond) {
+ unsigned REnd = R.getOffset() + Delta + R.getLength();
+ unsigned End = Offset + Text.size();
+ if (REnd > End) {
+ Length += REnd - End;
+ MergeSecond = false;
+ }
+ StringRef TextRef = Text;
+ StringRef Head = TextRef.substr(0, R.getOffset() + Delta - Offset);
+ StringRef Tail = TextRef.substr(REnd - Offset);
+ Text = (Head + R.getReplacementText() + Tail).str();
+ Delta += R.getReplacementText().size() - R.getLength();
+ } else {
+ unsigned End = Offset + Length;
+ StringRef RText = R.getReplacementText();
+ StringRef Tail = RText.substr(End - R.getOffset());
+ Text = (Text + Tail).str();
+ if (R.getOffset() + RText.size() > End) {
+ Length = R.getOffset() + R.getLength() - Offset;
+ MergeSecond = true;
+ } else {
+ Length += R.getLength() - RText.size();
+ }
+ DeltaFirst += RText.size() - R.getLength();
+ }
+ }
+
+ // Returns 'true' if 'R' starts strictly after the MergedReplacement and thus
+ // doesn't need to be merged.
+ bool endsBefore(const Replacement &R) const {
+ if (MergeSecond)
+ return Offset + Text.size() < R.getOffset() + Delta;
+ return Offset + Length < R.getOffset();
+ }
+
+ // Returns 'true' if an element from the second set should be merged next.
+ bool mergeSecond() const { return MergeSecond; }
+
+ int deltaFirst() const { return DeltaFirst; }
+ Replacement asReplacement() const { return {FilePath, Offset, Length, Text}; }
+
+private:
+ bool MergeSecond;
+
+ // Amount of characters that elements from 'Second' need to be shifted by in
+ // order to refer to the original text.
+ int Delta;
+
+ // Sum of all deltas (text-length - length) of elements from 'First' merged
+ // into this element. This is used to update 'Delta' once the
+ // MergedReplacement is completed.
+ int DeltaFirst;
+
+ // Data of the actually merged replacement. FilePath and Offset aren't changed
+ // as the element is only extended to the right.
+ const StringRef FilePath;
+ const unsigned Offset;
+ unsigned Length;
+ std::string Text;
+};
+
+} // namespace
+
+Replacements Replacements::merge(const Replacements &ReplacesToMerge) const {
+ if (empty() || ReplacesToMerge.empty())
+ return empty() ? ReplacesToMerge : *this;
+
+ auto &First = Replaces;
+ auto &Second = ReplacesToMerge.Replaces;
+ // Delta is the amount of characters that replacements from 'Second' need to
+ // be shifted so that their offsets refer to the original text.
+ int Delta = 0;
+ ReplacementsImpl Result;
+
+ // Iterate over both sets and always add the next element (smallest total
+ // Offset) from either 'First' or 'Second'. Merge that element with
+ // subsequent replacements as long as they overlap. See more details in the
+ // comment on MergedReplacement.
+ for (auto FirstI = First.begin(), SecondI = Second.begin();
+ FirstI != First.end() || SecondI != Second.end();) {
+ bool NextIsFirst = SecondI == Second.end() ||
+ (FirstI != First.end() &&
+ FirstI->getOffset() < SecondI->getOffset() + Delta);
+ MergedReplacement Merged(NextIsFirst ? *FirstI : *SecondI, NextIsFirst,
+ Delta);
+ ++(NextIsFirst ? FirstI : SecondI);
+
+ while ((Merged.mergeSecond() && SecondI != Second.end()) ||
+ (!Merged.mergeSecond() && FirstI != First.end())) {
+ auto &I = Merged.mergeSecond() ? SecondI : FirstI;
+ if (Merged.endsBefore(*I))
+ break;
+ Merged.merge(*I);
+ ++I;
+ }
+ Delta -= Merged.deltaFirst();
+ Result.insert(Merged.asReplacement());
+ }
+ return Replacements(Result.begin(), Result.end());
+}
+
+// Combines overlapping ranges in \p Ranges and sorts the combined ranges.
+// Returns a set of non-overlapping and sorted ranges that is equivalent to
+// \p Ranges.
+static std::vector<Range> combineAndSortRanges(std::vector<Range> Ranges) {
+ llvm::sort(Ranges, [](const Range &LHS, const Range &RHS) {
+ if (LHS.getOffset() != RHS.getOffset())
+ return LHS.getOffset() < RHS.getOffset();
+ return LHS.getLength() < RHS.getLength();
+ });
+ std::vector<Range> Result;
+ for (const auto &R : Ranges) {
+ if (Result.empty() ||
+ Result.back().getOffset() + Result.back().getLength() < R.getOffset()) {
+ Result.push_back(R);
+ } else {
+ unsigned NewEnd =
+ std::max(Result.back().getOffset() + Result.back().getLength(),
+ R.getOffset() + R.getLength());
+ Result[Result.size() - 1] =
+ Range(Result.back().getOffset(), NewEnd - Result.back().getOffset());
+ }
+ }
+ return Result;
+}
+
+namespace clang {
+namespace tooling {
+
+std::vector<Range>
+calculateRangesAfterReplacements(const Replacements &Replaces,
+ const std::vector<Range> &Ranges) {
+ // To calculate the new ranges,
+ // - Turn \p Ranges into Replacements at (offset, length) with an empty
+ // (unimportant) replacement text of length "length".
+ // - Merge with \p Replaces.
+ // - The new ranges will be the affected ranges of the merged replacements.
+ auto MergedRanges = combineAndSortRanges(Ranges);
+ if (Replaces.empty())
+ 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));
+ }
+ return FakeReplaces.merge(Replaces).getAffectedRanges();
+}
+
+} // namespace tooling
+} // namespace clang
+
+std::vector<Range> Replacements::getAffectedRanges() const {
+ std::vector<Range> ChangedRanges;
+ int Shift = 0;
+ for (const auto &R : Replaces) {
+ unsigned Offset = R.getOffset() + Shift;
+ unsigned Length = R.getReplacementText().size();
+ Shift += Length - R.getLength();
+ ChangedRanges.push_back(Range(Offset, Length));
+ }
+ return combineAndSortRanges(ChangedRanges);
+}
+
+unsigned Replacements::getShiftedCodePosition(unsigned Position) const {
+ unsigned Offset = 0;
+ for (const auto &R : Replaces) {
+ if (R.getOffset() + R.getLength() <= Position) {
+ Offset += R.getReplacementText().size() - R.getLength();
+ continue;
+ }
+ if (R.getOffset() < Position &&
+ R.getOffset() + R.getReplacementText().size() <= Position) {
+ Position = R.getOffset() + R.getReplacementText().size();
+ if (!R.getReplacementText().empty())
+ Position--;
+ }
+ break;
+ }
+ return Position + Offset;
+}
+
+namespace clang {
+namespace tooling {
+
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
+ bool Result = true;
+ for (auto I = Replaces.rbegin(), E = Replaces.rend(); I != E; ++I) {
+ if (I->isApplicable()) {
+ Result = I->apply(Rewrite) && Result;
+ } else {
+ Result = false;
+ }
+ }
+ return Result;
+}
+
+llvm::Expected<std::string> applyAllReplacements(StringRef Code,
+ const Replacements &Replaces) {
+ if (Replaces.empty())
+ return Code.str();
+
+ IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new llvm::vfs::InMemoryFileSystem);
+ FileManager Files(FileSystemOptions(), InMemoryFileSystem);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ new DiagnosticOptions);
+ SourceManager SourceMgr(Diagnostics, Files);
+ Rewriter Rewrite(SourceMgr, LangOptions());
+ InMemoryFileSystem->addFile(
+ "<stdin>", 0, llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>"));
+ FileID ID = SourceMgr.createFileID(Files.getFile("<stdin>"), SourceLocation(),
+ clang::SrcMgr::C_User);
+ for (auto I = Replaces.rbegin(), E = Replaces.rend(); I != E; ++I) {
+ Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
+ I->getReplacementText());
+ if (!Replace.apply(Rewrite))
+ return llvm::make_error<ReplacementError>(
+ replacement_error::fail_to_apply, Replace);
+ }
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ Rewrite.getEditBuffer(ID).write(OS);
+ OS.flush();
+ return Result;
+}
+
+std::map<std::string, Replacements> groupReplacementsByFile(
+ FileManager &FileMgr,
+ const std::map<std::string, Replacements> &FileToReplaces) {
+ std::map<std::string, Replacements> Result;
+ llvm::SmallPtrSet<const FileEntry *, 16> ProcessedFileEntries;
+ for (const auto &Entry : FileToReplaces) {
+ const FileEntry *FE = FileMgr.getFile(Entry.first);
+ if (!FE)
+ llvm::errs() << "File path " << Entry.first << " is invalid.\n";
+ else if (ProcessedFileEntries.insert(FE).second)
+ Result[Entry.first] = std::move(Entry.second);
+ }
+ return Result;
+}
+
+} // namespace tooling
+} // namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Execution.cpp b/contrib/llvm/tools/clang/lib/Tooling/Execution.cpp
new file mode 100644
index 000000000000..9ddb18a57b46
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Execution.cpp
@@ -0,0 +1,108 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/ToolExecutorPluginRegistry.h"
+#include "clang/Tooling/Tooling.h"
+
+LLVM_INSTANTIATE_REGISTRY(clang::tooling::ToolExecutorPluginRegistry)
+
+namespace clang {
+namespace tooling {
+
+llvm::cl::opt<std::string>
+ ExecutorName("executor", llvm::cl::desc("The name of the executor to use."),
+ llvm::cl::init("standalone"));
+
+void InMemoryToolResults::addResult(StringRef Key, StringRef Value) {
+ KVResults.push_back({Strings.save(Key), Strings.save(Value)});
+}
+
+std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
+InMemoryToolResults::AllKVResults() {
+ return KVResults;
+}
+
+void InMemoryToolResults::forEachResult(
+ llvm::function_ref<void(StringRef Key, StringRef Value)> Callback) {
+ for (const auto &KV : KVResults) {
+ Callback(KV.first, KV.second);
+ }
+}
+
+void ExecutionContext::reportResult(StringRef Key, StringRef Value) {
+ Results->addResult(Key, Value);
+}
+
+llvm::Error
+ToolExecutor::execute(std::unique_ptr<FrontendActionFactory> Action) {
+ return execute(std::move(Action), ArgumentsAdjuster());
+}
+
+llvm::Error ToolExecutor::execute(std::unique_ptr<FrontendActionFactory> Action,
+ ArgumentsAdjuster Adjuster) {
+ std::vector<
+ std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
+ Actions;
+ Actions.emplace_back(std::move(Action), std::move(Adjuster));
+ return execute(Actions);
+}
+
+namespace internal {
+llvm::Expected<std::unique_ptr<ToolExecutor>>
+createExecutorFromCommandLineArgsImpl(int &argc, const char **argv,
+ llvm::cl::OptionCategory &Category,
+ const char *Overview) {
+ auto OptionsParser =
+ CommonOptionsParser::create(argc, argv, Category, llvm::cl::ZeroOrMore,
+ /*Overview=*/Overview);
+ if (!OptionsParser)
+ return OptionsParser.takeError();
+ for (auto I = ToolExecutorPluginRegistry::begin(),
+ E = ToolExecutorPluginRegistry::end();
+ I != E; ++I) {
+ if (I->getName() != ExecutorName) {
+ continue;
+ }
+ std::unique_ptr<ToolExecutorPlugin> Plugin(I->instantiate());
+ llvm::Expected<std::unique_ptr<ToolExecutor>> Executor =
+ Plugin->create(*OptionsParser);
+ if (!Executor) {
+ return llvm::make_error<llvm::StringError>(
+ llvm::Twine("Failed to create '") + I->getName() +
+ "': " + llvm::toString(Executor.takeError()) + "\n",
+ llvm::inconvertibleErrorCode());
+ }
+ return std::move(*Executor);
+ }
+ return llvm::make_error<llvm::StringError>(
+ llvm::Twine("Executor \"") + ExecutorName + "\" is not registered.",
+ llvm::inconvertibleErrorCode());
+}
+} // end namespace internal
+
+llvm::Expected<std::unique_ptr<ToolExecutor>>
+createExecutorFromCommandLineArgs(int &argc, const char **argv,
+ llvm::cl::OptionCategory &Category,
+ const char *Overview) {
+ return internal::createExecutorFromCommandLineArgsImpl(argc, argv, Category,
+ Overview);
+}
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the StandaloneToolExecutorPlugin etc.
+extern volatile int StandaloneToolExecutorAnchorSource;
+extern volatile int AllTUsToolExecutorAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED StandaloneToolExecutorAnchorDest =
+ StandaloneToolExecutorAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED AllTUsToolExecutorAnchorDest =
+ AllTUsToolExecutorAnchorSource;
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/FileMatchTrie.cpp b/contrib/llvm/tools/clang/lib/Tooling/FileMatchTrie.cpp
new file mode 100644
index 000000000000..202b3f00f3fb
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/FileMatchTrie.cpp
@@ -0,0 +1,196 @@
+//===- FileMatchTrie.cpp --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation of a FileMatchTrie.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/FileMatchTrie.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <vector>
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+/// Default \c PathComparator using \c llvm::sys::fs::equivalent().
+struct DefaultPathComparator : public PathComparator {
+ bool equivalent(StringRef FileA, StringRef FileB) const override {
+ return FileA == FileB || llvm::sys::fs::equivalent(FileA, FileB);
+ }
+};
+
+} // namespace
+
+namespace clang {
+namespace tooling {
+
+/// A node of the \c FileMatchTrie.
+///
+/// Each node has storage for up to one path and a map mapping a path segment to
+/// child nodes. The trie starts with an empty root node.
+class FileMatchTrieNode {
+public:
+ /// Inserts 'NewPath' into this trie. \c ConsumedLength denotes
+ /// the number of \c NewPath's trailing characters already consumed during
+ /// recursion.
+ ///
+ /// An insert of a path
+ /// 'p'starts at the root node and does the following:
+ /// - If the node is empty, insert 'p' into its storage and abort.
+ /// - If the node has a path 'p2' but no children, take the last path segment
+ /// 's' of 'p2', put a new child into the map at 's' an insert the rest of
+ /// 'p2' there.
+ /// - Insert a new child for the last segment of 'p' and insert the rest of
+ /// 'p' there.
+ ///
+ /// An insert operation is linear in the number of a path's segments.
+ void insert(StringRef NewPath, unsigned ConsumedLength = 0) {
+ // We cannot put relative paths into the FileMatchTrie as then a path can be
+ // a postfix of another path, violating a core assumption of the trie.
+ if (llvm::sys::path::is_relative(NewPath))
+ return;
+ if (Path.empty()) {
+ // This is an empty leaf. Store NewPath and return.
+ Path = NewPath;
+ return;
+ }
+ if (Children.empty()) {
+ // This is a leaf, ignore duplicate entry if 'Path' equals 'NewPath'.
+ if (NewPath == Path)
+ return;
+ // Make this a node and create a child-leaf with 'Path'.
+ StringRef Element(llvm::sys::path::filename(
+ StringRef(Path).drop_back(ConsumedLength)));
+ Children[Element].Path = Path;
+ }
+ StringRef Element(llvm::sys::path::filename(
+ StringRef(NewPath).drop_back(ConsumedLength)));
+ Children[Element].insert(NewPath, ConsumedLength + Element.size() + 1);
+ }
+
+ /// Tries to find the node under this \c FileMatchTrieNode that best
+ /// matches 'FileName'.
+ ///
+ /// If multiple paths fit 'FileName' equally well, \c IsAmbiguous is set to
+ /// \c true and an empty string is returned. If no path fits 'FileName', an
+ /// empty string is returned. \c ConsumedLength denotes the number of
+ /// \c Filename's trailing characters already consumed during recursion.
+ ///
+ /// To find the best matching node for a given path 'p', the
+ /// \c findEquivalent() function is called recursively for each path segment
+ /// (back to front) of 'p' until a node 'n' is reached that does not ..
+ /// - .. have children. In this case it is checked
+ /// whether the stored path is equivalent to 'p'. If yes, the best match is
+ /// found. Otherwise continue with the parent node as if this node did not
+ /// exist.
+ /// - .. a child matching the next path segment. In this case, all children of
+ /// 'n' are an equally good match for 'p'. All children are of 'n' are found
+ /// recursively and their equivalence to 'p' is determined. If none are
+ /// equivalent, continue with the parent node as if 'n' didn't exist. If one
+ /// is equivalent, the best match is found. Otherwise, report and ambigiuity
+ /// error.
+ StringRef findEquivalent(const PathComparator& Comparator,
+ StringRef FileName,
+ bool &IsAmbiguous,
+ unsigned ConsumedLength = 0) const {
+ if (Children.empty()) {
+ if (Comparator.equivalent(StringRef(Path), FileName))
+ return StringRef(Path);
+ return {};
+ }
+ StringRef Element(llvm::sys::path::filename(FileName.drop_back(
+ ConsumedLength)));
+ llvm::StringMap<FileMatchTrieNode>::const_iterator MatchingChild =
+ Children.find(Element);
+ if (MatchingChild != Children.end()) {
+ StringRef Result = MatchingChild->getValue().findEquivalent(
+ Comparator, FileName, IsAmbiguous,
+ ConsumedLength + Element.size() + 1);
+ if (!Result.empty() || IsAmbiguous)
+ return Result;
+ }
+ std::vector<StringRef> AllChildren;
+ getAll(AllChildren, MatchingChild);
+ StringRef Result;
+ for (const auto &Child : AllChildren) {
+ if (Comparator.equivalent(Child, FileName)) {
+ if (Result.empty()) {
+ Result = Child;
+ } else {
+ IsAmbiguous = true;
+ return {};
+ }
+ }
+ }
+ return Result;
+ }
+
+private:
+ /// Gets all paths under this FileMatchTrieNode.
+ void getAll(std::vector<StringRef> &Results,
+ llvm::StringMap<FileMatchTrieNode>::const_iterator Except) const {
+ if (Path.empty())
+ return;
+ if (Children.empty()) {
+ Results.push_back(StringRef(Path));
+ return;
+ }
+ for (llvm::StringMap<FileMatchTrieNode>::const_iterator
+ It = Children.begin(), E = Children.end();
+ It != E; ++It) {
+ if (It == Except)
+ continue;
+ It->getValue().getAll(Results, Children.end());
+ }
+ }
+
+ // The stored absolute path in this node. Only valid for leaf nodes, i.e.
+ // nodes where Children.empty().
+ std::string Path;
+
+ // The children of this node stored in a map based on the next path segment.
+ llvm::StringMap<FileMatchTrieNode> Children;
+};
+
+} // namespace tooling
+} // namespace clang
+
+FileMatchTrie::FileMatchTrie()
+ : Root(new FileMatchTrieNode), Comparator(new DefaultPathComparator()) {}
+
+FileMatchTrie::FileMatchTrie(PathComparator *Comparator)
+ : Root(new FileMatchTrieNode), Comparator(Comparator) {}
+
+FileMatchTrie::~FileMatchTrie() {
+ delete Root;
+}
+
+void FileMatchTrie::insert(StringRef NewPath) {
+ Root->insert(NewPath);
+}
+
+StringRef FileMatchTrie::findEquivalent(StringRef FileName,
+ raw_ostream &Error) const {
+ if (llvm::sys::path::is_relative(FileName)) {
+ Error << "Cannot resolve relative paths";
+ return {};
+ }
+ bool IsAmbiguous = false;
+ StringRef Result = Root->findEquivalent(*Comparator, FileName, IsAmbiguous);
+ if (IsAmbiguous)
+ Error << "Path is ambiguous";
+ return Result;
+}
diff --git a/contrib/llvm/tools/clang/lib/Tooling/FixIt.cpp b/contrib/llvm/tools/clang/lib/Tooling/FixIt.cpp
new file mode 100644
index 000000000000..70942c5ac845
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/FixIt.cpp
@@ -0,0 +1,31 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains implementations of utitilies to ease source code rewriting
+// by providing helper functions related to FixItHint.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Tooling/FixIt.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace tooling {
+namespace fixit {
+
+namespace internal {
+StringRef getText(SourceRange Range, const ASTContext &Context) {
+ return Lexer::getSourceText(CharSourceRange::getTokenRange(Range),
+ Context.getSourceManager(),
+ Context.getLangOpts());
+}
+} // end namespace internal
+
+} // end namespace fixit
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp b/contrib/llvm/tools/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
new file mode 100644
index 000000000000..c74ad0b9cd56
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
@@ -0,0 +1,330 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Inclusions/HeaderIncludes.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/FormatVariadic.h"
+
+namespace clang {
+namespace tooling {
+namespace {
+
+LangOptions createLangOpts() {
+ LangOptions LangOpts;
+ LangOpts.CPlusPlus = 1;
+ LangOpts.CPlusPlus11 = 1;
+ LangOpts.CPlusPlus14 = 1;
+ LangOpts.LineComment = 1;
+ LangOpts.CXXOperatorNames = 1;
+ LangOpts.Bool = 1;
+ LangOpts.ObjC = 1;
+ LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
+ LangOpts.DeclSpecKeyword = 1; // To get __declspec.
+ LangOpts.WChar = 1; // To get wchar_t
+ return LangOpts;
+}
+
+// Returns the offset after skipping a sequence of tokens, matched by \p
+// GetOffsetAfterSequence, from the start of the code.
+// \p GetOffsetAfterSequence should be a function that matches a sequence of
+// tokens and returns an offset after the sequence.
+unsigned getOffsetAfterTokenSequence(
+ StringRef FileName, StringRef Code, const IncludeStyle &Style,
+ llvm::function_ref<unsigned(const SourceManager &, Lexer &, Token &)>
+ GetOffsetAfterSequence) {
+ SourceManagerForFile VirtualSM(FileName, Code);
+ SourceManager &SM = VirtualSM.get();
+ Lexer Lex(SM.getMainFileID(), SM.getBuffer(SM.getMainFileID()), SM,
+ createLangOpts());
+ Token Tok;
+ // Get the first token.
+ Lex.LexFromRawLexer(Tok);
+ return GetOffsetAfterSequence(SM, Lex, Tok);
+}
+
+// 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) {
+ 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);
+ if (Matched)
+ Lex.LexFromRawLexer(Tok);
+ return Matched;
+}
+
+void skipComments(Lexer &Lex, Token &Tok) {
+ while (Tok.is(tok::comment))
+ if (Lex.LexFromRawLexer(Tok))
+ return;
+}
+
+// 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.
+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;
+ });
+}
+
+// Check if a sequence of tokens is like
+// "#include ("header.h" | <header.h>)".
+// 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 checkAndConsumeInclusiveDirective(Lexer &Lex, Token &Tok) {
+ auto Matched = [&]() {
+ Lex.LexFromRawLexer(Tok);
+ return true;
+ };
+ if (Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
+ Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "include") {
+ if (Lex.LexFromRawLexer(Tok))
+ return false;
+ if (Tok.is(tok::string_literal))
+ return Matched();
+ if (Tok.is(tok::less)) {
+ while (!Lex.LexFromRawLexer(Tok) && Tok.isNot(tok::greater)) {
+ }
+ if (Tok.is(tok::greater))
+ return Matched();
+ }
+ }
+ return false;
+}
+
+// Returns the offset of the last #include directive after which a new
+// #include can be inserted. This ignores #include's after the #include block(s)
+// in the beginning of a file to avoid inserting headers into code sections
+// where new #include's should not be added by default.
+// These code sections include:
+// - raw string literals (containing #include).
+// - #if blocks.
+// - Special #include's among declarations (e.g. functions).
+//
+// If no #include after which a new #include can be inserted, this returns the
+// offset after skipping all comments from the start of the code.
+// Inserting after an #include is not allowed if it comes after code that is not
+// #include (e.g. pre-processing directive that is not #include, declarations).
+unsigned getMaxHeaderInsertionOffset(StringRef FileName, StringRef Code,
+ const IncludeStyle &Style) {
+ return getOffsetAfterTokenSequence(
+ FileName, Code, Style,
+ [](const SourceManager &SM, Lexer &Lex, Token Tok) {
+ skipComments(Lex, Tok);
+ unsigned MaxOffset = SM.getFileOffset(Tok.getLocation());
+ while (checkAndConsumeInclusiveDirective(Lex, Tok))
+ MaxOffset = SM.getFileOffset(Tok.getLocation());
+ return MaxOffset;
+ });
+}
+
+inline StringRef trimInclude(StringRef IncludeName) {
+ return IncludeName.trim("\"<>");
+}
+
+const char IncludeRegexPattern[] =
+ R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
+
+} // anonymous namespace
+
+IncludeCategoryManager::IncludeCategoryManager(const IncludeStyle &Style,
+ StringRef FileName)
+ : Style(Style), FileName(FileName) {
+ FileStem = llvm::sys::path::stem(FileName);
+ for (const auto &Category : Style.IncludeCategories)
+ CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
+ IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
+ FileName.endswith(".cpp") || FileName.endswith(".c++") ||
+ FileName.endswith(".cxx") || FileName.endswith(".m") ||
+ FileName.endswith(".mm");
+}
+
+int IncludeCategoryManager::getIncludePriority(StringRef IncludeName,
+ bool CheckMainHeader) const {
+ int Ret = INT_MAX;
+ for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i)
+ if (CategoryRegexs[i].match(IncludeName)) {
+ Ret = Style.IncludeCategories[i].Priority;
+ break;
+ }
+ if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName))
+ Ret = 0;
+ return Ret;
+}
+
+bool IncludeCategoryManager::isMainHeader(StringRef IncludeName) const {
+ if (!IncludeName.startswith("\""))
+ return false;
+ StringRef HeaderStem =
+ llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
+ if (FileStem.startswith(HeaderStem) ||
+ FileStem.startswith_lower(HeaderStem)) {
+ llvm::Regex MainIncludeRegex(HeaderStem.str() + Style.IncludeIsMainRegex,
+ llvm::Regex::IgnoreCase);
+ if (MainIncludeRegex.match(FileStem))
+ return true;
+ }
+ return false;
+}
+
+HeaderIncludes::HeaderIncludes(StringRef FileName, StringRef Code,
+ const IncludeStyle &Style)
+ : FileName(FileName), Code(Code), FirstIncludeOffset(-1),
+ MinInsertOffset(
+ getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style)),
+ MaxInsertOffset(MinInsertOffset +
+ getMaxHeaderInsertionOffset(
+ FileName, Code.drop_front(MinInsertOffset), Style)),
+ Categories(Style, FileName),
+ IncludeRegex(llvm::Regex(IncludeRegexPattern)) {
+ // Add 0 for main header and INT_MAX for headers that are not in any
+ // category.
+ Priorities = {0, INT_MAX};
+ for (const auto &Category : Style.IncludeCategories)
+ Priorities.insert(Category.Priority);
+ SmallVector<StringRef, 32> Lines;
+ Code.drop_front(MinInsertOffset).split(Lines, "\n");
+
+ unsigned Offset = MinInsertOffset;
+ unsigned NextLineOffset;
+ SmallVector<StringRef, 4> Matches;
+ for (auto Line : Lines) {
+ NextLineOffset = std::min(Code.size(), Offset + Line.size() + 1);
+ if (IncludeRegex.match(Line, &Matches)) {
+ // If this is the last line without trailing newline, we need to make
+ // sure we don't delete across the file boundary.
+ addExistingInclude(
+ Include(Matches[2],
+ tooling::Range(
+ Offset, std::min(Line.size() + 1, Code.size() - Offset))),
+ NextLineOffset);
+ }
+ Offset = NextLineOffset;
+ }
+
+ // Populate CategoryEndOfssets:
+ // - Ensure that CategoryEndOffset[Highest] is always populated.
+ // - If CategoryEndOffset[Priority] isn't set, use the next higher value
+ // that is set, up to CategoryEndOffset[Highest].
+ auto Highest = Priorities.begin();
+ if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
+ if (FirstIncludeOffset >= 0)
+ CategoryEndOffsets[*Highest] = FirstIncludeOffset;
+ else
+ CategoryEndOffsets[*Highest] = MinInsertOffset;
+ }
+ // By this point, CategoryEndOffset[Highest] is always set appropriately:
+ // - to an appropriate location before/after existing #includes, or
+ // - to right after the header guard, or
+ // - to the beginning of the file.
+ for (auto I = ++Priorities.begin(), E = Priorities.end(); I != E; ++I)
+ if (CategoryEndOffsets.find(*I) == CategoryEndOffsets.end())
+ CategoryEndOffsets[*I] = CategoryEndOffsets[*std::prev(I)];
+}
+
+// \p Offset: the start of the line following this include directive.
+void HeaderIncludes::addExistingInclude(Include IncludeToAdd,
+ unsigned NextLineOffset) {
+ auto Iter =
+ ExistingIncludes.try_emplace(trimInclude(IncludeToAdd.Name)).first;
+ Iter->second.push_back(std::move(IncludeToAdd));
+ auto &CurInclude = Iter->second.back();
+ // The header name with quotes or angle brackets.
+ // Only record the offset of current #include if we can insert after it.
+ if (CurInclude.R.getOffset() <= MaxInsertOffset) {
+ int Priority = Categories.getIncludePriority(
+ CurInclude.Name, /*CheckMainHeader=*/FirstIncludeOffset < 0);
+ CategoryEndOffsets[Priority] = NextLineOffset;
+ IncludesByPriority[Priority].push_back(&CurInclude);
+ if (FirstIncludeOffset < 0)
+ FirstIncludeOffset = CurInclude.R.getOffset();
+ }
+}
+
+llvm::Optional<tooling::Replacement>
+HeaderIncludes::insert(llvm::StringRef IncludeName, bool IsAngled) const {
+ assert(IncludeName == trimInclude(IncludeName));
+ // If a <header> ("header") already exists in code, "header" (<header>) with
+ // different quotation will still be inserted.
+ // FIXME: figure out if this is the best behavior.
+ auto It = ExistingIncludes.find(IncludeName);
+ if (It != ExistingIncludes.end())
+ for (const auto &Inc : It->second)
+ if ((IsAngled && StringRef(Inc.Name).startswith("<")) ||
+ (!IsAngled && StringRef(Inc.Name).startswith("\"")))
+ return llvm::None;
+ std::string Quoted =
+ llvm::formatv(IsAngled ? "<{0}>" : "\"{0}\"", IncludeName);
+ StringRef QuotedName = Quoted;
+ int Priority = Categories.getIncludePriority(
+ QuotedName, /*CheckMainHeader=*/FirstIncludeOffset < 0);
+ auto CatOffset = CategoryEndOffsets.find(Priority);
+ assert(CatOffset != CategoryEndOffsets.end());
+ unsigned InsertOffset = CatOffset->second; // Fall back offset
+ auto Iter = IncludesByPriority.find(Priority);
+ if (Iter != IncludesByPriority.end()) {
+ for (const auto *Inc : Iter->second) {
+ if (QuotedName < Inc->Name) {
+ InsertOffset = Inc->R.getOffset();
+ break;
+ }
+ }
+ }
+ assert(InsertOffset <= Code.size());
+ std::string NewInclude = llvm::formatv("#include {0}\n", QuotedName);
+ // When inserting headers at end of the code, also append '\n' to the code
+ // if it does not end with '\n'.
+ // FIXME: when inserting multiple #includes at the end of code, only one
+ // newline should be added.
+ if (InsertOffset == Code.size() && (!Code.empty() && Code.back() != '\n'))
+ NewInclude = "\n" + NewInclude;
+ return tooling::Replacement(FileName, InsertOffset, 0, NewInclude);
+}
+
+tooling::Replacements HeaderIncludes::remove(llvm::StringRef IncludeName,
+ bool IsAngled) const {
+ assert(IncludeName == trimInclude(IncludeName));
+ tooling::Replacements Result;
+ auto Iter = ExistingIncludes.find(IncludeName);
+ if (Iter == ExistingIncludes.end())
+ return Result;
+ for (const auto &Inc : Iter->second) {
+ if ((IsAngled && StringRef(Inc.Name).startswith("\"")) ||
+ (!IsAngled && StringRef(Inc.Name).startswith("<")))
+ continue;
+ llvm::Error Err = Result.add(tooling::Replacement(
+ FileName, Inc.R.getOffset(), Inc.R.getLength(), ""));
+ if (Err) {
+ auto ErrMsg = "Unexpected conflicts in #include deletions: " +
+ llvm::toString(std::move(Err));
+ llvm_unreachable(ErrMsg.c_str());
+ }
+ }
+ return Result;
+}
+
+
+} // namespace tooling
+} // namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Inclusions/IncludeStyle.cpp b/contrib/llvm/tools/clang/lib/Tooling/Inclusions/IncludeStyle.cpp
new file mode 100644
index 000000000000..3597710f1f6e
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Inclusions/IncludeStyle.cpp
@@ -0,0 +1,31 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Inclusions/IncludeStyle.h"
+
+using clang::tooling::IncludeStyle;
+
+namespace llvm {
+namespace yaml {
+
+void MappingTraits<IncludeStyle::IncludeCategory>::mapping(
+ IO &IO, IncludeStyle::IncludeCategory &Category) {
+ IO.mapOptional("Regex", Category.Regex);
+ IO.mapOptional("Priority", Category.Priority);
+}
+
+void ScalarEnumerationTraits<IncludeStyle::IncludeBlocksStyle>::enumeration(
+ IO &IO, IncludeStyle::IncludeBlocksStyle &Value) {
+ IO.enumCase(Value, "Preserve", IncludeStyle::IBS_Preserve);
+ IO.enumCase(Value, "Merge", IncludeStyle::IBS_Merge);
+ IO.enumCase(Value, "Regroup", IncludeStyle::IBS_Regroup);
+}
+
+} // namespace yaml
+} // namespace llvm
diff --git a/contrib/llvm/tools/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/contrib/llvm/tools/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
new file mode 100644
index 000000000000..4d0d84f660a2
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -0,0 +1,547 @@
+//===- InterpolatingCompilationDatabase.cpp ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// InterpolatingCompilationDatabase wraps another CompilationDatabase and
+// attempts to heuristically determine appropriate compile commands for files
+// that are not included, such as headers or newly created files.
+//
+// Motivating cases include:
+// Header files that live next to their implementation files. These typically
+// share a base filename. (libclang/CXString.h, libclang/CXString.cpp).
+// Some projects separate headers from includes. Filenames still typically
+// match, maybe other path segments too. (include/llvm/IR/Use.h, lib/IR/Use.cc).
+// Matches are sometimes only approximate (Sema.h, SemaDecl.cpp). This goes
+// for directories too (Support/Unix/Process.inc, lib/Support/Process.cpp).
+// Even if we can't find a "right" compile command, even a random one from
+// the project will tend to get important flags like -I and -x right.
+//
+// We "borrow" the compile command for the closest available file:
+// - points are awarded if the filename matches (ignoring extension)
+// - points are awarded if the directory structure matches
+// - ties are broken by length of path prefix match
+//
+// The compile command is adjusted, replacing the filename and removing output
+// file arguments. The -x and -std flags may be affected too.
+//
+// Source language is a tricky issue: is it OK to use a .c file's command
+// for building a .cc file? What language is a .h file in?
+// - We only consider compile commands for c-family languages as candidates.
+// - For files whose language is implied by the filename (e.g. .m, .hpp)
+// we prefer candidates from the same language.
+// If we must cross languages, we drop any -x and -std flags.
+// - For .h files, candidates from any c-family language are acceptable.
+// We use the candidate's language, inserting e.g. -x c++-header.
+//
+// This class is only useful when wrapping databases that can enumerate all
+// their compile commands. If getAllFilenames() is empty, no inference occurs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Options.h"
+#include "clang/Driver/Types.h"
+#include "clang/Frontend/LangStandard.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+
+namespace clang {
+namespace tooling {
+namespace {
+using namespace llvm;
+namespace types = clang::driver::types;
+namespace path = llvm::sys::path;
+
+// The length of the prefix these two strings have in common.
+size_t matchingPrefix(StringRef L, StringRef R) {
+ size_t Limit = std::min(L.size(), R.size());
+ for (size_t I = 0; I < Limit; ++I)
+ if (L[I] != R[I])
+ return I;
+ return Limit;
+}
+
+// A comparator for searching SubstringWithIndexes with std::equal_range etc.
+// Optionaly prefix semantics: compares equal if the key is a prefix.
+template <bool Prefix> struct Less {
+ bool operator()(StringRef Key, std::pair<StringRef, size_t> Value) const {
+ StringRef V = Prefix ? Value.first.substr(0, Key.size()) : Value.first;
+ return Key < V;
+ }
+ bool operator()(std::pair<StringRef, size_t> Value, StringRef Key) const {
+ StringRef V = Prefix ? Value.first.substr(0, Key.size()) : Value.first;
+ return V < Key;
+ }
+};
+
+// Infer type from filename. If we might have gotten it wrong, set *Certain.
+// *.h will be inferred as a C header, but not certain.
+types::ID guessType(StringRef Filename, bool *Certain = nullptr) {
+ // path::extension is ".cpp", lookupTypeForExtension wants "cpp".
+ auto Lang =
+ types::lookupTypeForExtension(path::extension(Filename).substr(1));
+ if (Certain)
+ *Certain = Lang != types::TY_CHeader && Lang != types::TY_INVALID;
+ return Lang;
+}
+
+// Return Lang as one of the canonical supported types.
+// e.g. c-header --> c; fortran --> TY_INVALID
+static types::ID foldType(types::ID Lang) {
+ switch (Lang) {
+ case types::TY_C:
+ case types::TY_CHeader:
+ return types::TY_C;
+ case types::TY_ObjC:
+ case types::TY_ObjCHeader:
+ return types::TY_ObjC;
+ case types::TY_CXX:
+ case types::TY_CXXHeader:
+ return types::TY_CXX;
+ case types::TY_ObjCXX:
+ case types::TY_ObjCXXHeader:
+ return types::TY_ObjCXX;
+ default:
+ return types::TY_INVALID;
+ }
+}
+
+// A CompileCommand that can be applied to another file.
+struct TransferableCommand {
+ // Flags that should not apply to all files are stripped from CommandLine.
+ CompileCommand Cmd;
+ // Language detected from -x or the filename. Never TY_INVALID.
+ Optional<types::ID> Type;
+ // Standard specified by -std.
+ LangStandard::Kind Std = LangStandard::lang_unspecified;
+ // Whether the command line is for the cl-compatible driver.
+ bool ClangCLMode;
+
+ TransferableCommand(CompileCommand C)
+ : Cmd(std::move(C)), Type(guessType(Cmd.Filename)),
+ ClangCLMode(checkIsCLMode(Cmd.CommandLine)) {
+ std::vector<std::string> OldArgs = std::move(Cmd.CommandLine);
+ Cmd.CommandLine.clear();
+
+ // Wrap the old arguments in an InputArgList.
+ llvm::opt::InputArgList ArgList;
+ {
+ SmallVector<const char *, 16> TmpArgv;
+ for (const std::string &S : OldArgs)
+ TmpArgv.push_back(S.c_str());
+ ArgList = {TmpArgv.begin(), TmpArgv.end()};
+ }
+
+ // Parse the old args in order to strip out and record unwanted flags.
+ // We parse each argument individually so that we can retain the exact
+ // spelling of each argument; re-rendering is lossy for aliased flags.
+ // E.g. in CL mode, /W4 maps to -Wall.
+ auto OptTable = clang::driver::createDriverOptTable();
+ Cmd.CommandLine.emplace_back(OldArgs.front());
+ for (unsigned Pos = 1; Pos < OldArgs.size();) {
+ using namespace driver::options;
+
+ const unsigned OldPos = Pos;
+ std::unique_ptr<llvm::opt::Arg> Arg(OptTable->ParseOneArg(
+ ArgList, Pos,
+ /* Include */ClangCLMode ? CoreOption | CLOption : 0,
+ /* Exclude */ClangCLMode ? 0 : CLOption));
+
+ if (!Arg)
+ continue;
+
+ const llvm::opt::Option &Opt = Arg->getOption();
+
+ // Strip input and output files.
+ if (Opt.matches(OPT_INPUT) || Opt.matches(OPT_o) ||
+ (ClangCLMode && (Opt.matches(OPT__SLASH_Fa) ||
+ Opt.matches(OPT__SLASH_Fe) ||
+ Opt.matches(OPT__SLASH_Fi) ||
+ Opt.matches(OPT__SLASH_Fo))))
+ continue;
+
+ // Strip -x, but record the overridden language.
+ if (const auto GivenType = tryParseTypeArg(*Arg)) {
+ Type = *GivenType;
+ continue;
+ }
+
+ // Strip -std, but record the value.
+ if (const auto GivenStd = tryParseStdArg(*Arg)) {
+ if (*GivenStd != LangStandard::lang_unspecified)
+ Std = *GivenStd;
+ continue;
+ }
+
+ Cmd.CommandLine.insert(Cmd.CommandLine.end(),
+ OldArgs.data() + OldPos, OldArgs.data() + Pos);
+ }
+
+ if (Std != LangStandard::lang_unspecified) // -std take precedence over -x
+ Type = toType(LangStandard::getLangStandardForKind(Std).getLanguage());
+ Type = foldType(*Type);
+ // The contract is to store None instead of TY_INVALID.
+ if (Type == types::TY_INVALID)
+ Type = llvm::None;
+ }
+
+ // Produce a CompileCommand for \p filename, based on this one.
+ CompileCommand transferTo(StringRef Filename) const {
+ CompileCommand Result = Cmd;
+ Result.Filename = Filename;
+ bool TypeCertain;
+ auto TargetType = guessType(Filename, &TypeCertain);
+ // If the filename doesn't determine the language (.h), transfer with -x.
+ if (TargetType != types::TY_INVALID && !TypeCertain && Type) {
+ TargetType = types::onlyPrecompileType(TargetType) // header?
+ ? types::lookupHeaderTypeForSourceType(*Type)
+ : *Type;
+ if (ClangCLMode) {
+ const StringRef Flag = toCLFlag(TargetType);
+ if (!Flag.empty())
+ Result.CommandLine.push_back(Flag);
+ } else {
+ Result.CommandLine.push_back("-x");
+ Result.CommandLine.push_back(types::getTypeName(TargetType));
+ }
+ }
+ // --std flag may only be transferred if the language is the same.
+ // We may consider "translating" these, e.g. c++11 -> c11.
+ if (Std != LangStandard::lang_unspecified && foldType(TargetType) == Type) {
+ Result.CommandLine.emplace_back((
+ llvm::Twine(ClangCLMode ? "/std:" : "-std=") +
+ LangStandard::getLangStandardForKind(Std).getName()).str());
+ }
+ Result.CommandLine.push_back(Filename);
+ return Result;
+ }
+
+private:
+ // Determine whether the given command line is intended for the CL driver.
+ static bool checkIsCLMode(ArrayRef<std::string> CmdLine) {
+ // First look for --driver-mode.
+ for (StringRef S : llvm::reverse(CmdLine)) {
+ if (S.consume_front("--driver-mode="))
+ return S == "cl";
+ }
+
+ // Otherwise just check the clang executable file name.
+ return llvm::sys::path::stem(CmdLine.front()).endswith_lower("cl");
+ }
+
+ // Map the language from the --std flag to that of the -x flag.
+ static types::ID toType(InputKind::Language Lang) {
+ switch (Lang) {
+ case InputKind::C:
+ return types::TY_C;
+ case InputKind::CXX:
+ return types::TY_CXX;
+ case InputKind::ObjC:
+ return types::TY_ObjC;
+ case InputKind::ObjCXX:
+ return types::TY_ObjCXX;
+ default:
+ return types::TY_INVALID;
+ }
+ }
+
+ // Convert a file type to the matching CL-style type flag.
+ static StringRef toCLFlag(types::ID Type) {
+ switch (Type) {
+ case types::TY_C:
+ case types::TY_CHeader:
+ return "/TC";
+ case types::TY_CXX:
+ case types::TY_CXXHeader:
+ return "/TP";
+ default:
+ return StringRef();
+ }
+ }
+
+ // Try to interpret the argument as a type specifier, e.g. '-x'.
+ Optional<types::ID> tryParseTypeArg(const llvm::opt::Arg &Arg) {
+ const llvm::opt::Option &Opt = Arg.getOption();
+ using namespace driver::options;
+ if (ClangCLMode) {
+ if (Opt.matches(OPT__SLASH_TC) || Opt.matches(OPT__SLASH_Tc))
+ return types::TY_C;
+ if (Opt.matches(OPT__SLASH_TP) || Opt.matches(OPT__SLASH_Tp))
+ return types::TY_CXX;
+ } else {
+ if (Opt.matches(driver::options::OPT_x))
+ return types::lookupTypeForTypeSpecifier(Arg.getValue());
+ }
+ return None;
+ }
+
+ // Try to interpret the argument as '-std='.
+ Optional<LangStandard::Kind> tryParseStdArg(const llvm::opt::Arg &Arg) {
+ using namespace driver::options;
+ if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ)) {
+ return llvm::StringSwitch<LangStandard::Kind>(Arg.getValue())
+#define LANGSTANDARD(id, name, lang, ...) .Case(name, LangStandard::lang_##id)
+#define LANGSTANDARD_ALIAS(id, alias) .Case(alias, LangStandard::lang_##id)
+#include "clang/Frontend/LangStandards.def"
+#undef LANGSTANDARD_ALIAS
+#undef LANGSTANDARD
+ .Default(LangStandard::lang_unspecified);
+ }
+ return None;
+ }
+};
+
+// Given a filename, FileIndex picks the best matching file from the underlying
+// DB. This is the proxy file whose CompileCommand will be reused. The
+// heuristics incorporate file name, extension, and directory structure.
+// Strategy:
+// - Build indexes of each of the substrings we want to look up by.
+// These indexes are just sorted lists of the substrings.
+// - Each criterion corresponds to a range lookup into the index, so we only
+// need O(log N) string comparisons to determine scores.
+//
+// Apart from path proximity signals, also takes file extensions into account
+// when scoring the candidates.
+class FileIndex {
+public:
+ FileIndex(std::vector<std::string> Files)
+ : OriginalPaths(std::move(Files)), Strings(Arena) {
+ // Sort commands by filename for determinism (index is a tiebreaker later).
+ llvm::sort(OriginalPaths);
+ Paths.reserve(OriginalPaths.size());
+ Types.reserve(OriginalPaths.size());
+ Stems.reserve(OriginalPaths.size());
+ for (size_t I = 0; I < OriginalPaths.size(); ++I) {
+ StringRef Path = Strings.save(StringRef(OriginalPaths[I]).lower());
+
+ Paths.emplace_back(Path, I);
+ Types.push_back(foldType(guessType(Path)));
+ Stems.emplace_back(sys::path::stem(Path), I);
+ auto Dir = ++sys::path::rbegin(Path), DirEnd = sys::path::rend(Path);
+ for (int J = 0; J < DirectorySegmentsIndexed && Dir != DirEnd; ++J, ++Dir)
+ if (Dir->size() > ShortDirectorySegment) // not trivial ones
+ Components.emplace_back(*Dir, I);
+ }
+ llvm::sort(Paths);
+ llvm::sort(Stems);
+ llvm::sort(Components);
+ }
+
+ bool empty() const { return Paths.empty(); }
+
+ // Returns the path for the file that best fits OriginalFilename.
+ // Candidates with extensions matching PreferLanguage will be chosen over
+ // others (unless it's TY_INVALID, or all candidates are bad).
+ StringRef chooseProxy(StringRef OriginalFilename,
+ types::ID PreferLanguage) const {
+ assert(!empty() && "need at least one candidate!");
+ std::string Filename = OriginalFilename.lower();
+ auto Candidates = scoreCandidates(Filename);
+ std::pair<size_t, int> Best =
+ pickWinner(Candidates, Filename, PreferLanguage);
+
+ DEBUG_WITH_TYPE(
+ "interpolate",
+ llvm::dbgs() << "interpolate: chose " << OriginalPaths[Best.first]
+ << " as proxy for " << OriginalFilename << " preferring "
+ << (PreferLanguage == types::TY_INVALID
+ ? "none"
+ : types::getTypeName(PreferLanguage))
+ << " score=" << Best.second << "\n");
+ return OriginalPaths[Best.first];
+ }
+
+private:
+ using SubstringAndIndex = std::pair<StringRef, size_t>;
+ // Directory matching parameters: we look at the last two segments of the
+ // parent directory (usually the semantically significant ones in practice).
+ // We search only the last four of each candidate (for efficiency).
+ constexpr static int DirectorySegmentsIndexed = 4;
+ constexpr static int DirectorySegmentsQueried = 2;
+ constexpr static int ShortDirectorySegment = 1; // Only look at longer names.
+
+ // Award points to candidate entries that should be considered for the file.
+ // Returned keys are indexes into paths, and the values are (nonzero) scores.
+ DenseMap<size_t, int> scoreCandidates(StringRef Filename) const {
+ // Decompose Filename into the parts we care about.
+ // /some/path/complicated/project/Interesting.h
+ // [-prefix--][---dir---] [-dir-] [--stem---]
+ StringRef Stem = sys::path::stem(Filename);
+ llvm::SmallVector<StringRef, DirectorySegmentsQueried> Dirs;
+ llvm::StringRef Prefix;
+ auto Dir = ++sys::path::rbegin(Filename),
+ DirEnd = sys::path::rend(Filename);
+ for (int I = 0; I < DirectorySegmentsQueried && Dir != DirEnd; ++I, ++Dir) {
+ if (Dir->size() > ShortDirectorySegment)
+ Dirs.push_back(*Dir);
+ Prefix = Filename.substr(0, Dir - DirEnd);
+ }
+
+ // Now award points based on lookups into our various indexes.
+ DenseMap<size_t, int> Candidates; // Index -> score.
+ auto Award = [&](int Points, ArrayRef<SubstringAndIndex> Range) {
+ for (const auto &Entry : Range)
+ Candidates[Entry.second] += Points;
+ };
+ // Award one point if the file's basename is a prefix of the candidate,
+ // and another if it's an exact match (so exact matches get two points).
+ Award(1, indexLookup</*Prefix=*/true>(Stem, Stems));
+ Award(1, indexLookup</*Prefix=*/false>(Stem, Stems));
+ // For each of the last few directories in the Filename, award a point
+ // if it's present in the candidate.
+ for (StringRef Dir : Dirs)
+ Award(1, indexLookup</*Prefix=*/false>(Dir, Components));
+ // Award one more point if the whole rest of the path matches.
+ if (sys::path::root_directory(Prefix) != Prefix)
+ Award(1, indexLookup</*Prefix=*/true>(Prefix, Paths));
+ return Candidates;
+ }
+
+ // Pick a single winner from the set of scored candidates.
+ // Returns (index, score).
+ std::pair<size_t, int> pickWinner(const DenseMap<size_t, int> &Candidates,
+ StringRef Filename,
+ types::ID PreferredLanguage) const {
+ struct ScoredCandidate {
+ size_t Index;
+ bool Preferred;
+ int Points;
+ size_t PrefixLength;
+ };
+ // Choose the best candidate by (preferred, points, prefix length, alpha).
+ ScoredCandidate Best = {size_t(-1), false, 0, 0};
+ for (const auto &Candidate : Candidates) {
+ ScoredCandidate S;
+ S.Index = Candidate.first;
+ S.Preferred = PreferredLanguage == types::TY_INVALID ||
+ PreferredLanguage == Types[S.Index];
+ S.Points = Candidate.second;
+ if (!S.Preferred && Best.Preferred)
+ continue;
+ if (S.Preferred == Best.Preferred) {
+ if (S.Points < Best.Points)
+ continue;
+ if (S.Points == Best.Points) {
+ S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
+ if (S.PrefixLength < Best.PrefixLength)
+ continue;
+ // hidden heuristics should at least be deterministic!
+ if (S.PrefixLength == Best.PrefixLength)
+ if (S.Index > Best.Index)
+ continue;
+ }
+ }
+ // PrefixLength was only set above if actually needed for a tiebreak.
+ // But it definitely needs to be set to break ties in the future.
+ S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
+ Best = S;
+ }
+ // Edge case: no candidate got any points.
+ // We ignore PreferredLanguage at this point (not ideal).
+ if (Best.Index == size_t(-1))
+ return {longestMatch(Filename, Paths).second, 0};
+ return {Best.Index, Best.Points};
+ }
+
+ // Returns the range within a sorted index that compares equal to Key.
+ // If Prefix is true, it's instead the range starting with Key.
+ template <bool Prefix>
+ ArrayRef<SubstringAndIndex>
+ indexLookup(StringRef Key, ArrayRef<SubstringAndIndex> Idx) const {
+ // Use pointers as iteratiors to ease conversion of result to ArrayRef.
+ auto Range = std::equal_range(Idx.data(), Idx.data() + Idx.size(), Key,
+ Less<Prefix>());
+ return {Range.first, Range.second};
+ }
+
+ // Performs a point lookup into a nonempty index, returning a longest match.
+ SubstringAndIndex longestMatch(StringRef Key,
+ ArrayRef<SubstringAndIndex> Idx) const {
+ assert(!Idx.empty());
+ // Longest substring match will be adjacent to a direct lookup.
+ auto It =
+ std::lower_bound(Idx.begin(), Idx.end(), SubstringAndIndex{Key, 0});
+ if (It == Idx.begin())
+ return *It;
+ if (It == Idx.end())
+ return *--It;
+ // Have to choose between It and It-1
+ size_t Prefix = matchingPrefix(Key, It->first);
+ size_t PrevPrefix = matchingPrefix(Key, (It - 1)->first);
+ return Prefix > PrevPrefix ? *It : *--It;
+ }
+
+ // Original paths, everything else is in lowercase.
+ std::vector<std::string> OriginalPaths;
+ BumpPtrAllocator Arena;
+ StringSaver Strings;
+ // Indexes of candidates by certain substrings.
+ // String is lowercase and sorted, index points into OriginalPaths.
+ std::vector<SubstringAndIndex> Paths; // Full path.
+ // Lang types obtained by guessing on the corresponding path. I-th element is
+ // a type for the I-th path.
+ std::vector<types::ID> Types;
+ std::vector<SubstringAndIndex> Stems; // Basename, without extension.
+ std::vector<SubstringAndIndex> Components; // Last path components.
+};
+
+// The actual CompilationDatabase wrapper delegates to its inner database.
+// If no match, looks up a proxy file in FileIndex and transfers its
+// command to the requested file.
+class InterpolatingCompilationDatabase : public CompilationDatabase {
+public:
+ InterpolatingCompilationDatabase(std::unique_ptr<CompilationDatabase> Inner)
+ : Inner(std::move(Inner)), Index(this->Inner->getAllFiles()) {}
+
+ std::vector<CompileCommand>
+ getCompileCommands(StringRef Filename) const override {
+ auto Known = Inner->getCompileCommands(Filename);
+ if (Index.empty() || !Known.empty())
+ return Known;
+ bool TypeCertain;
+ auto Lang = guessType(Filename, &TypeCertain);
+ if (!TypeCertain)
+ Lang = types::TY_INVALID;
+ auto ProxyCommands =
+ Inner->getCompileCommands(Index.chooseProxy(Filename, foldType(Lang)));
+ if (ProxyCommands.empty())
+ return {};
+ return {TransferableCommand(ProxyCommands[0]).transferTo(Filename)};
+ }
+
+ std::vector<std::string> getAllFiles() const override {
+ return Inner->getAllFiles();
+ }
+
+ std::vector<CompileCommand> getAllCompileCommands() const override {
+ return Inner->getAllCompileCommands();
+ }
+
+private:
+ std::unique_ptr<CompilationDatabase> Inner;
+ FileIndex Index;
+};
+
+} // namespace
+
+std::unique_ptr<CompilationDatabase>
+inferMissingCompileCommands(std::unique_ptr<CompilationDatabase> Inner) {
+ return llvm::make_unique<InterpolatingCompilationDatabase>(std::move(Inner));
+}
+
+} // namespace tooling
+} // namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/JSONCompilationDatabase.cpp b/contrib/llvm/tools/clang/lib/Tooling/JSONCompilationDatabase.cpp
new file mode 100644
index 000000000000..b0feaa229c11
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/JSONCompilationDatabase.cpp
@@ -0,0 +1,384 @@
+//===- JSONCompilationDatabase.cpp ----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation of the JSONCompilationDatabase.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/JSONCompilationDatabase.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+/// A parser for escaped strings of command line arguments.
+///
+/// Assumes \-escaping for quoted arguments (see the documentation of
+/// unescapeCommandLine(...)).
+class CommandLineArgumentParser {
+ public:
+ CommandLineArgumentParser(StringRef CommandLine)
+ : Input(CommandLine), Position(Input.begin()-1) {}
+
+ std::vector<std::string> parse() {
+ bool HasMoreInput = true;
+ while (HasMoreInput && nextNonWhitespace()) {
+ std::string Argument;
+ HasMoreInput = parseStringInto(Argument);
+ CommandLine.push_back(Argument);
+ }
+ return CommandLine;
+ }
+
+ private:
+ // All private methods return true if there is more input available.
+
+ bool parseStringInto(std::string &String) {
+ do {
+ if (*Position == '"') {
+ if (!parseDoubleQuotedStringInto(String)) return false;
+ } else if (*Position == '\'') {
+ if (!parseSingleQuotedStringInto(String)) return false;
+ } else {
+ if (!parseFreeStringInto(String)) return false;
+ }
+ } while (*Position != ' ');
+ return true;
+ }
+
+ bool parseDoubleQuotedStringInto(std::string &String) {
+ if (!next()) return false;
+ while (*Position != '"') {
+ if (!skipEscapeCharacter()) return false;
+ String.push_back(*Position);
+ if (!next()) return false;
+ }
+ return next();
+ }
+
+ bool parseSingleQuotedStringInto(std::string &String) {
+ if (!next()) return false;
+ while (*Position != '\'') {
+ String.push_back(*Position);
+ if (!next()) return false;
+ }
+ return next();
+ }
+
+ bool parseFreeStringInto(std::string &String) {
+ do {
+ if (!skipEscapeCharacter()) return false;
+ String.push_back(*Position);
+ if (!next()) return false;
+ } while (*Position != ' ' && *Position != '"' && *Position != '\'');
+ return true;
+ }
+
+ bool skipEscapeCharacter() {
+ if (*Position == '\\') {
+ return next();
+ }
+ return true;
+ }
+
+ bool nextNonWhitespace() {
+ do {
+ if (!next()) return false;
+ } while (*Position == ' ');
+ return true;
+ }
+
+ bool next() {
+ ++Position;
+ return Position != Input.end();
+ }
+
+ const StringRef Input;
+ StringRef::iterator Position;
+ std::vector<std::string> CommandLine;
+};
+
+std::vector<std::string> unescapeCommandLine(JSONCommandLineSyntax Syntax,
+ StringRef EscapedCommandLine) {
+ if (Syntax == JSONCommandLineSyntax::AutoDetect) {
+ Syntax = JSONCommandLineSyntax::Gnu;
+ llvm::Triple Triple(llvm::sys::getProcessTriple());
+ if (Triple.getOS() == llvm::Triple::OSType::Win32) {
+ // Assume Windows command line parsing on Win32 unless the triple
+ // explicitly tells us otherwise.
+ if (!Triple.hasEnvironment() ||
+ Triple.getEnvironment() == llvm::Triple::EnvironmentType::MSVC)
+ Syntax = JSONCommandLineSyntax::Windows;
+ }
+ }
+
+ if (Syntax == JSONCommandLineSyntax::Windows) {
+ llvm::BumpPtrAllocator Alloc;
+ llvm::StringSaver Saver(Alloc);
+ llvm::SmallVector<const char *, 64> T;
+ llvm::cl::TokenizeWindowsCommandLine(EscapedCommandLine, Saver, T);
+ std::vector<std::string> Result(T.begin(), T.end());
+ return Result;
+ }
+ assert(Syntax == JSONCommandLineSyntax::Gnu);
+ CommandLineArgumentParser parser(EscapedCommandLine);
+ return parser.parse();
+}
+
+// This plugin locates a nearby compile_command.json file, and also infers
+// compile commands for files not present in the database.
+class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
+ std::unique_ptr<CompilationDatabase>
+ loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
+ SmallString<1024> JSONDatabasePath(Directory);
+ llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
+ auto Base = JSONCompilationDatabase::loadFromFile(
+ JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect);
+ return Base ? inferMissingCompileCommands(std::move(Base)) : nullptr;
+ }
+};
+
+} // namespace
+
+// Register the JSONCompilationDatabasePlugin with the
+// CompilationDatabasePluginRegistry using this statically initialized variable.
+static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
+X("json-compilation-database", "Reads JSON formatted compilation databases");
+
+namespace clang {
+namespace tooling {
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the JSONCompilationDatabasePlugin.
+volatile int JSONAnchorSource = 0;
+
+} // namespace tooling
+} // namespace clang
+
+std::unique_ptr<JSONCompilationDatabase>
+JSONCompilationDatabase::loadFromFile(StringRef FilePath,
+ std::string &ErrorMessage,
+ JSONCommandLineSyntax Syntax) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
+ llvm::MemoryBuffer::getFile(FilePath);
+ if (std::error_code Result = DatabaseBuffer.getError()) {
+ ErrorMessage = "Error while opening JSON database: " + Result.message();
+ return nullptr;
+ }
+ std::unique_ptr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(std::move(*DatabaseBuffer), Syntax));
+ if (!Database->parse(ErrorMessage))
+ return nullptr;
+ return Database;
+}
+
+std::unique_ptr<JSONCompilationDatabase>
+JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
+ std::string &ErrorMessage,
+ JSONCommandLineSyntax Syntax) {
+ std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
+ llvm::MemoryBuffer::getMemBuffer(DatabaseString));
+ std::unique_ptr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(std::move(DatabaseBuffer), Syntax));
+ if (!Database->parse(ErrorMessage))
+ return nullptr;
+ return Database;
+}
+
+std::vector<CompileCommand>
+JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
+ SmallString<128> NativeFilePath;
+ llvm::sys::path::native(FilePath, NativeFilePath);
+
+ std::string Error;
+ llvm::raw_string_ostream ES(Error);
+ StringRef Match = MatchTrie.findEquivalent(NativeFilePath, ES);
+ if (Match.empty())
+ return {};
+ const auto CommandsRefI = IndexByFile.find(Match);
+ if (CommandsRefI == IndexByFile.end())
+ return {};
+ std::vector<CompileCommand> Commands;
+ getCommands(CommandsRefI->getValue(), Commands);
+ return Commands;
+}
+
+std::vector<std::string>
+JSONCompilationDatabase::getAllFiles() const {
+ std::vector<std::string> Result;
+ for (const auto &CommandRef : IndexByFile)
+ Result.push_back(CommandRef.first().str());
+ return Result;
+}
+
+std::vector<CompileCommand>
+JSONCompilationDatabase::getAllCompileCommands() const {
+ std::vector<CompileCommand> Commands;
+ getCommands(AllCommands, Commands);
+ return Commands;
+}
+
+static std::vector<std::string>
+nodeToCommandLine(JSONCommandLineSyntax Syntax,
+ const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
+ SmallString<1024> Storage;
+ if (Nodes.size() == 1)
+ return unescapeCommandLine(Syntax, Nodes[0]->getValue(Storage));
+ std::vector<std::string> Arguments;
+ for (const auto *Node : Nodes)
+ Arguments.push_back(Node->getValue(Storage));
+ return Arguments;
+}
+
+void JSONCompilationDatabase::getCommands(
+ ArrayRef<CompileCommandRef> CommandsRef,
+ std::vector<CompileCommand> &Commands) const {
+ for (const auto &CommandRef : CommandsRef) {
+ SmallString<8> DirectoryStorage;
+ SmallString<32> FilenameStorage;
+ SmallString<32> OutputStorage;
+ auto Output = std::get<3>(CommandRef);
+ Commands.emplace_back(
+ std::get<0>(CommandRef)->getValue(DirectoryStorage),
+ std::get<1>(CommandRef)->getValue(FilenameStorage),
+ nodeToCommandLine(Syntax, std::get<2>(CommandRef)),
+ Output ? Output->getValue(OutputStorage) : "");
+ }
+}
+
+bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
+ llvm::yaml::document_iterator I = YAMLStream.begin();
+ if (I == YAMLStream.end()) {
+ ErrorMessage = "Error while parsing YAML.";
+ return false;
+ }
+ llvm::yaml::Node *Root = I->getRoot();
+ if (!Root) {
+ ErrorMessage = "Error while parsing YAML.";
+ return false;
+ }
+ auto *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
+ if (!Array) {
+ ErrorMessage = "Expected array.";
+ return false;
+ }
+ for (auto &NextObject : *Array) {
+ auto *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
+ if (!Object) {
+ ErrorMessage = "Expected object.";
+ return false;
+ }
+ llvm::yaml::ScalarNode *Directory = nullptr;
+ llvm::Optional<std::vector<llvm::yaml::ScalarNode *>> Command;
+ llvm::yaml::ScalarNode *File = nullptr;
+ llvm::yaml::ScalarNode *Output = nullptr;
+ for (auto& NextKeyValue : *Object) {
+ auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
+ if (!KeyString) {
+ ErrorMessage = "Expected strings as key.";
+ return false;
+ }
+ SmallString<10> KeyStorage;
+ StringRef KeyValue = KeyString->getValue(KeyStorage);
+ llvm::yaml::Node *Value = NextKeyValue.getValue();
+ if (!Value) {
+ ErrorMessage = "Expected value.";
+ return false;
+ }
+ auto *ValueString = dyn_cast<llvm::yaml::ScalarNode>(Value);
+ auto *SequenceString = dyn_cast<llvm::yaml::SequenceNode>(Value);
+ if (KeyValue == "arguments" && !SequenceString) {
+ ErrorMessage = "Expected sequence as value.";
+ return false;
+ } else if (KeyValue != "arguments" && !ValueString) {
+ ErrorMessage = "Expected string as value.";
+ return false;
+ }
+ if (KeyValue == "directory") {
+ Directory = ValueString;
+ } else if (KeyValue == "arguments") {
+ Command = std::vector<llvm::yaml::ScalarNode *>();
+ for (auto &Argument : *SequenceString) {
+ auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
+ if (!Scalar) {
+ ErrorMessage = "Only strings are allowed in 'arguments'.";
+ return false;
+ }
+ Command->push_back(Scalar);
+ }
+ } else if (KeyValue == "command") {
+ if (!Command)
+ Command = std::vector<llvm::yaml::ScalarNode *>(1, ValueString);
+ } else if (KeyValue == "file") {
+ File = ValueString;
+ } else if (KeyValue == "output") {
+ Output = ValueString;
+ } else {
+ ErrorMessage = ("Unknown key: \"" +
+ KeyString->getRawValue() + "\"").str();
+ return false;
+ }
+ }
+ if (!File) {
+ ErrorMessage = "Missing key: \"file\".";
+ return false;
+ }
+ if (!Command) {
+ ErrorMessage = "Missing key: \"command\" or \"arguments\".";
+ return false;
+ }
+ if (!Directory) {
+ ErrorMessage = "Missing key: \"directory\".";
+ return false;
+ }
+ SmallString<8> FileStorage;
+ StringRef FileName = File->getValue(FileStorage);
+ SmallString<128> NativeFilePath;
+ if (llvm::sys::path::is_relative(FileName)) {
+ SmallString<8> DirectoryStorage;
+ SmallString<128> AbsolutePath(
+ Directory->getValue(DirectoryStorage));
+ llvm::sys::path::append(AbsolutePath, FileName);
+ llvm::sys::path::native(AbsolutePath, NativeFilePath);
+ } else {
+ llvm::sys::path::native(FileName, NativeFilePath);
+ }
+ auto Cmd = CompileCommandRef(Directory, File, *Command, Output);
+ IndexByFile[NativeFilePath].push_back(Cmd);
+ AllCommands.push_back(Cmd);
+ MatchTrie.insert(NativeFilePath);
+ }
+ return true;
+}
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring.cpp
new file mode 100644
index 000000000000..db34c952d794
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring.cpp
@@ -0,0 +1,104 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements tools to support refactorings.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_os_ostream.h"
+
+namespace clang {
+namespace tooling {
+
+RefactoringTool::RefactoringTool(
+ const CompilationDatabase &Compilations, ArrayRef<std::string> SourcePaths,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps)
+ : ClangTool(Compilations, SourcePaths, std::move(PCHContainerOps)) {}
+
+std::map<std::string, Replacements> &RefactoringTool::getReplacements() {
+ return FileToReplaces;
+}
+
+int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) {
+ if (int Result = run(ActionFactory)) {
+ return Result;
+ }
+
+ LangOptions DefaultLangOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
+ &*DiagOpts, &DiagnosticPrinter, false);
+ SourceManager Sources(Diagnostics, getFiles());
+ Rewriter Rewrite(Sources, DefaultLangOptions);
+
+ if (!applyAllReplacements(Rewrite)) {
+ llvm::errs() << "Skipped some replacements.\n";
+ }
+
+ return saveRewrittenFiles(Rewrite);
+}
+
+bool RefactoringTool::applyAllReplacements(Rewriter &Rewrite) {
+ bool Result = true;
+ for (const auto &Entry : groupReplacementsByFile(
+ Rewrite.getSourceMgr().getFileManager(), FileToReplaces))
+ Result = tooling::applyAllReplacements(Entry.second, Rewrite) && Result;
+ return Result;
+}
+
+int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
+ return Rewrite.overwriteChangedFiles() ? 1 : 0;
+}
+
+bool formatAndApplyAllReplacements(
+ const std::map<std::string, Replacements> &FileToReplaces,
+ Rewriter &Rewrite, StringRef Style) {
+ SourceManager &SM = Rewrite.getSourceMgr();
+ FileManager &Files = SM.getFileManager();
+
+ bool Result = true;
+ for (const auto &FileAndReplaces : groupReplacementsByFile(
+ Rewrite.getSourceMgr().getFileManager(), FileToReplaces)) {
+ const std::string &FilePath = FileAndReplaces.first;
+ auto &CurReplaces = FileAndReplaces.second;
+
+ const FileEntry *Entry = Files.getFile(FilePath);
+ FileID ID = SM.getOrCreateFileID(Entry, SrcMgr::C_User);
+ StringRef Code = SM.getBufferData(ID);
+
+ auto CurStyle = format::getStyle(Style, FilePath, "LLVM");
+ if (!CurStyle) {
+ llvm::errs() << llvm::toString(CurStyle.takeError()) << "\n";
+ return false;
+ }
+
+ auto NewReplacements =
+ format::formatReplacements(Code, CurReplaces, *CurStyle);
+ if (!NewReplacements) {
+ llvm::errs() << llvm::toString(NewReplacements.takeError()) << "\n";
+ return false;
+ }
+ Result = applyAllReplacements(*NewReplacements, Rewrite) && Result;
+ }
+ return Result;
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelection.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelection.cpp
new file mode 100644
index 000000000000..b8f996d8218c
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelection.cpp
@@ -0,0 +1,451 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/SaveAndRestore.h"
+
+using namespace clang;
+using namespace tooling;
+using ast_type_traits::DynTypedNode;
+
+namespace {
+
+CharSourceRange getLexicalDeclRange(Decl *D, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (!isa<ObjCImplDecl>(D))
+ return CharSourceRange::getTokenRange(D->getSourceRange());
+ // Objective-C implementation declarations end at the '@' instead of the 'end'
+ // keyword. Use the lexer to find the location right after 'end'.
+ SourceRange R = D->getSourceRange();
+ SourceLocation LocAfterEnd = Lexer::findLocationAfterToken(
+ R.getEnd(), tok::raw_identifier, SM, LangOpts,
+ /*SkipTrailingWhitespaceAndNewLine=*/false);
+ return LocAfterEnd.isValid()
+ ? CharSourceRange::getCharRange(R.getBegin(), LocAfterEnd)
+ : CharSourceRange::getTokenRange(R);
+}
+
+/// Constructs the tree of selected AST nodes that either contain the location
+/// of the cursor or overlap with the selection range.
+class ASTSelectionFinder
+ : public LexicallyOrderedRecursiveASTVisitor<ASTSelectionFinder> {
+public:
+ ASTSelectionFinder(SourceRange Selection, FileID TargetFile,
+ const ASTContext &Context)
+ : LexicallyOrderedRecursiveASTVisitor(Context.getSourceManager()),
+ SelectionBegin(Selection.getBegin()),
+ SelectionEnd(Selection.getBegin() == Selection.getEnd()
+ ? SourceLocation()
+ : Selection.getEnd()),
+ TargetFile(TargetFile), Context(Context) {
+ // The TU decl is the root of the selected node tree.
+ SelectionStack.push_back(
+ SelectedASTNode(DynTypedNode::create(*Context.getTranslationUnitDecl()),
+ SourceSelectionKind::None));
+ }
+
+ Optional<SelectedASTNode> getSelectedASTNode() {
+ assert(SelectionStack.size() == 1 && "stack was not popped");
+ SelectedASTNode Result = std::move(SelectionStack.back());
+ SelectionStack.pop_back();
+ if (Result.Children.empty())
+ return None;
+ return std::move(Result);
+ }
+
+ bool TraversePseudoObjectExpr(PseudoObjectExpr *E) {
+ // Avoid traversing the semantic expressions. They should be handled by
+ // looking through the appropriate opaque expressions in order to build
+ // a meaningful selection tree.
+ llvm::SaveAndRestore<bool> LookThrough(LookThroughOpaqueValueExprs, true);
+ return TraverseStmt(E->getSyntacticForm());
+ }
+
+ bool TraverseOpaqueValueExpr(OpaqueValueExpr *E) {
+ if (!LookThroughOpaqueValueExprs)
+ return true;
+ llvm::SaveAndRestore<bool> LookThrough(LookThroughOpaqueValueExprs, false);
+ return TraverseStmt(E->getSourceExpr());
+ }
+
+ bool TraverseDecl(Decl *D) {
+ if (isa<TranslationUnitDecl>(D))
+ return LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
+ if (D->isImplicit())
+ return true;
+
+ // Check if this declaration is written in the file of interest.
+ const SourceRange DeclRange = D->getSourceRange();
+ const SourceManager &SM = Context.getSourceManager();
+ SourceLocation FileLoc;
+ if (DeclRange.getBegin().isMacroID() && !DeclRange.getEnd().isMacroID())
+ FileLoc = DeclRange.getEnd();
+ else
+ FileLoc = SM.getSpellingLoc(DeclRange.getBegin());
+ if (SM.getFileID(FileLoc) != TargetFile)
+ return true;
+
+ SourceSelectionKind SelectionKind =
+ selectionKindFor(getLexicalDeclRange(D, SM, Context.getLangOpts()));
+ SelectionStack.push_back(
+ SelectedASTNode(DynTypedNode::create(*D), SelectionKind));
+ LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
+ popAndAddToSelectionIfSelected(SelectionKind);
+
+ if (DeclRange.getEnd().isValid() &&
+ SM.isBeforeInTranslationUnit(SelectionEnd.isValid() ? SelectionEnd
+ : SelectionBegin,
+ DeclRange.getEnd())) {
+ // Stop early when we've reached a declaration after the selection.
+ return false;
+ }
+ return true;
+ }
+
+ bool TraverseStmt(Stmt *S) {
+ if (!S)
+ return true;
+ if (auto *Opaque = dyn_cast<OpaqueValueExpr>(S))
+ return TraverseOpaqueValueExpr(Opaque);
+ // Avoid selecting implicit 'this' expressions.
+ if (auto *TE = dyn_cast<CXXThisExpr>(S)) {
+ if (TE->isImplicit())
+ return true;
+ }
+ // FIXME (Alex Lorenz): Improve handling for macro locations.
+ SourceSelectionKind SelectionKind =
+ selectionKindFor(CharSourceRange::getTokenRange(S->getSourceRange()));
+ SelectionStack.push_back(
+ SelectedASTNode(DynTypedNode::create(*S), SelectionKind));
+ LexicallyOrderedRecursiveASTVisitor::TraverseStmt(S);
+ popAndAddToSelectionIfSelected(SelectionKind);
+ return true;
+ }
+
+private:
+ void popAndAddToSelectionIfSelected(SourceSelectionKind SelectionKind) {
+ SelectedASTNode Node = std::move(SelectionStack.back());
+ SelectionStack.pop_back();
+ if (SelectionKind != SourceSelectionKind::None || !Node.Children.empty())
+ SelectionStack.back().Children.push_back(std::move(Node));
+ }
+
+ SourceSelectionKind selectionKindFor(CharSourceRange Range) {
+ SourceLocation End = Range.getEnd();
+ const SourceManager &SM = Context.getSourceManager();
+ if (Range.isTokenRange())
+ End = Lexer::getLocForEndOfToken(End, 0, SM, Context.getLangOpts());
+ if (!SourceLocation::isPairOfFileLocations(Range.getBegin(), End))
+ return SourceSelectionKind::None;
+ if (!SelectionEnd.isValid()) {
+ // Do a quick check when the selection is of length 0.
+ if (SM.isPointWithin(SelectionBegin, Range.getBegin(), End))
+ return SourceSelectionKind::ContainsSelection;
+ return SourceSelectionKind::None;
+ }
+ bool HasStart = SM.isPointWithin(SelectionBegin, Range.getBegin(), End);
+ bool HasEnd = SM.isPointWithin(SelectionEnd, Range.getBegin(), End);
+ if (HasStart && HasEnd)
+ return SourceSelectionKind::ContainsSelection;
+ if (SM.isPointWithin(Range.getBegin(), SelectionBegin, SelectionEnd) &&
+ SM.isPointWithin(End, SelectionBegin, SelectionEnd))
+ return SourceSelectionKind::InsideSelection;
+ // Ensure there's at least some overlap with the 'start'/'end' selection
+ // types.
+ if (HasStart && SelectionBegin != End)
+ return SourceSelectionKind::ContainsSelectionStart;
+ if (HasEnd && SelectionEnd != Range.getBegin())
+ return SourceSelectionKind::ContainsSelectionEnd;
+
+ return SourceSelectionKind::None;
+ }
+
+ const SourceLocation SelectionBegin, SelectionEnd;
+ FileID TargetFile;
+ const ASTContext &Context;
+ std::vector<SelectedASTNode> SelectionStack;
+ /// Controls whether we can traverse through the OpaqueValueExpr. This is
+ /// typically enabled during the traversal of syntactic form for
+ /// PseudoObjectExprs.
+ bool LookThroughOpaqueValueExprs = false;
+};
+
+} // end anonymous namespace
+
+Optional<SelectedASTNode>
+clang::tooling::findSelectedASTNodes(const ASTContext &Context,
+ SourceRange SelectionRange) {
+ assert(SelectionRange.isValid() &&
+ SourceLocation::isPairOfFileLocations(SelectionRange.getBegin(),
+ SelectionRange.getEnd()) &&
+ "Expected a file range");
+ FileID TargetFile =
+ Context.getSourceManager().getFileID(SelectionRange.getBegin());
+ assert(Context.getSourceManager().getFileID(SelectionRange.getEnd()) ==
+ TargetFile &&
+ "selection range must span one file");
+
+ ASTSelectionFinder Visitor(SelectionRange, TargetFile, Context);
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ return Visitor.getSelectedASTNode();
+}
+
+static const char *selectionKindToString(SourceSelectionKind Kind) {
+ switch (Kind) {
+ case SourceSelectionKind::None:
+ return "none";
+ case SourceSelectionKind::ContainsSelection:
+ return "contains-selection";
+ case SourceSelectionKind::ContainsSelectionStart:
+ return "contains-selection-start";
+ case SourceSelectionKind::ContainsSelectionEnd:
+ return "contains-selection-end";
+ case SourceSelectionKind::InsideSelection:
+ return "inside";
+ }
+ llvm_unreachable("invalid selection kind");
+}
+
+static void dump(const SelectedASTNode &Node, llvm::raw_ostream &OS,
+ unsigned Indent = 0) {
+ OS.indent(Indent * 2);
+ if (const Decl *D = Node.Node.get<Decl>()) {
+ OS << D->getDeclKindName() << "Decl";
+ if (const auto *ND = dyn_cast<NamedDecl>(D))
+ OS << " \"" << ND->getNameAsString() << '"';
+ } else if (const Stmt *S = Node.Node.get<Stmt>()) {
+ OS << S->getStmtClassName();
+ }
+ OS << ' ' << selectionKindToString(Node.SelectionKind) << "\n";
+ for (const auto &Child : Node.Children)
+ dump(Child, OS, Indent + 1);
+}
+
+void SelectedASTNode::dump(llvm::raw_ostream &OS) const { ::dump(*this, OS); }
+
+/// Returns true if the given node has any direct children with the following
+/// selection kind.
+///
+/// Note: The direct children also include children of direct children with the
+/// "None" selection kind.
+static bool hasAnyDirectChildrenWithKind(const SelectedASTNode &Node,
+ SourceSelectionKind Kind) {
+ assert(Kind != SourceSelectionKind::None && "invalid predicate!");
+ for (const auto &Child : Node.Children) {
+ if (Child.SelectionKind == Kind)
+ return true;
+ if (Child.SelectionKind == SourceSelectionKind::None)
+ return hasAnyDirectChildrenWithKind(Child, Kind);
+ }
+ return false;
+}
+
+namespace {
+struct SelectedNodeWithParents {
+ SelectedASTNode::ReferenceType Node;
+ llvm::SmallVector<SelectedASTNode::ReferenceType, 8> Parents;
+
+ /// Canonicalizes the given selection by selecting different related AST nodes
+ /// when it makes sense to do so.
+ void canonicalize();
+};
+
+enum SelectionCanonicalizationAction { KeepSelection, SelectParent };
+
+/// Returns the canonicalization action which should be applied to the
+/// selected statement.
+SelectionCanonicalizationAction
+getSelectionCanonizalizationAction(const Stmt *S, const Stmt *Parent) {
+ // Select the parent expression when:
+ // - The string literal in ObjC string literal is selected, e.g.:
+ // @"test" becomes @"test"
+ // ~~~~~~ ~~~~~~~
+ if (isa<StringLiteral>(S) && isa<ObjCStringLiteral>(Parent))
+ return SelectParent;
+ // The entire call should be selected when just the member expression
+ // that refers to the method or the decl ref that refers to the function
+ // is selected.
+ // f.call(args) becomes f.call(args)
+ // ~~~~ ~~~~~~~~~~~~
+ // func(args) becomes func(args)
+ // ~~~~ ~~~~~~~~~~
+ else if (const auto *CE = dyn_cast<CallExpr>(Parent)) {
+ if ((isa<MemberExpr>(S) || isa<DeclRefExpr>(S)) &&
+ CE->getCallee()->IgnoreImpCasts() == S)
+ return SelectParent;
+ }
+ // FIXME: Syntactic form -> Entire pseudo-object expr.
+ return KeepSelection;
+}
+
+} // end anonymous namespace
+
+void SelectedNodeWithParents::canonicalize() {
+ const Stmt *S = Node.get().Node.get<Stmt>();
+ assert(S && "non statement selection!");
+ const Stmt *Parent = Parents[Parents.size() - 1].get().Node.get<Stmt>();
+ if (!Parent)
+ return;
+
+ // Look through the implicit casts in the parents.
+ unsigned ParentIndex = 1;
+ for (; (ParentIndex + 1) <= Parents.size() && isa<ImplicitCastExpr>(Parent);
+ ++ParentIndex) {
+ const Stmt *NewParent =
+ Parents[Parents.size() - ParentIndex - 1].get().Node.get<Stmt>();
+ if (!NewParent)
+ break;
+ Parent = NewParent;
+ }
+
+ switch (getSelectionCanonizalizationAction(S, Parent)) {
+ case SelectParent:
+ Node = Parents[Parents.size() - ParentIndex];
+ for (; ParentIndex != 0; --ParentIndex)
+ Parents.pop_back();
+ break;
+ case KeepSelection:
+ break;
+ }
+}
+
+/// Finds the set of bottom-most selected AST nodes that are in the selection
+/// tree with the specified selection kind.
+///
+/// For example, given the following selection tree:
+///
+/// FunctionDecl "f" contains-selection
+/// CompoundStmt contains-selection [#1]
+/// CallExpr inside
+/// ImplicitCastExpr inside
+/// DeclRefExpr inside
+/// IntegerLiteral inside
+/// IntegerLiteral inside
+/// FunctionDecl "f2" contains-selection
+/// CompoundStmt contains-selection [#2]
+/// CallExpr inside
+/// ImplicitCastExpr inside
+/// DeclRefExpr inside
+/// IntegerLiteral inside
+/// IntegerLiteral inside
+///
+/// This function will find references to nodes #1 and #2 when searching for the
+/// \c ContainsSelection kind.
+static void findDeepestWithKind(
+ const SelectedASTNode &ASTSelection,
+ llvm::SmallVectorImpl<SelectedNodeWithParents> &MatchingNodes,
+ SourceSelectionKind Kind,
+ llvm::SmallVectorImpl<SelectedASTNode::ReferenceType> &ParentStack) {
+ if (ASTSelection.Node.get<DeclStmt>()) {
+ // Select the entire decl stmt when any of its child declarations is the
+ // bottom-most.
+ for (const auto &Child : ASTSelection.Children) {
+ if (!hasAnyDirectChildrenWithKind(Child, Kind)) {
+ MatchingNodes.push_back(SelectedNodeWithParents{
+ std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
+ return;
+ }
+ }
+ } else {
+ if (!hasAnyDirectChildrenWithKind(ASTSelection, Kind)) {
+ // This node is the bottom-most.
+ MatchingNodes.push_back(SelectedNodeWithParents{
+ std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
+ return;
+ }
+ }
+ // Search in the children.
+ ParentStack.push_back(std::cref(ASTSelection));
+ for (const auto &Child : ASTSelection.Children)
+ findDeepestWithKind(Child, MatchingNodes, Kind, ParentStack);
+ ParentStack.pop_back();
+}
+
+static void findDeepestWithKind(
+ const SelectedASTNode &ASTSelection,
+ llvm::SmallVectorImpl<SelectedNodeWithParents> &MatchingNodes,
+ SourceSelectionKind Kind) {
+ llvm::SmallVector<SelectedASTNode::ReferenceType, 16> ParentStack;
+ findDeepestWithKind(ASTSelection, MatchingNodes, Kind, ParentStack);
+}
+
+Optional<CodeRangeASTSelection>
+CodeRangeASTSelection::create(SourceRange SelectionRange,
+ const SelectedASTNode &ASTSelection) {
+ // Code range is selected when the selection range is not empty.
+ if (SelectionRange.getBegin() == SelectionRange.getEnd())
+ return None;
+ llvm::SmallVector<SelectedNodeWithParents, 4> ContainSelection;
+ findDeepestWithKind(ASTSelection, ContainSelection,
+ SourceSelectionKind::ContainsSelection);
+ // We are looking for a selection in one body of code, so let's focus on
+ // one matching result.
+ if (ContainSelection.size() != 1)
+ return None;
+ SelectedNodeWithParents &Selected = ContainSelection[0];
+ if (!Selected.Node.get().Node.get<Stmt>())
+ return None;
+ const Stmt *CodeRangeStmt = Selected.Node.get().Node.get<Stmt>();
+ if (!isa<CompoundStmt>(CodeRangeStmt)) {
+ Selected.canonicalize();
+ return CodeRangeASTSelection(Selected.Node, Selected.Parents,
+ /*AreChildrenSelected=*/false);
+ }
+ // FIXME (Alex L): First selected SwitchCase means that first case statement.
+ // is selected actually
+ // (See https://github.com/apple/swift-clang & CompoundStmtRange).
+
+ // FIXME (Alex L): Tweak selection rules for compound statements, see:
+ // https://github.com/apple/swift-clang/blob/swift-4.1-branch/lib/Tooling/
+ // Refactor/ASTSlice.cpp#L513
+ // The user selected multiple statements in a compound statement.
+ Selected.Parents.push_back(Selected.Node);
+ return CodeRangeASTSelection(Selected.Node, Selected.Parents,
+ /*AreChildrenSelected=*/true);
+}
+
+static bool isFunctionLikeDeclaration(const Decl *D) {
+ // FIXME (Alex L): Test for BlockDecl.
+ return isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D);
+}
+
+bool CodeRangeASTSelection::isInFunctionLikeBodyOfCode() const {
+ bool IsPrevCompound = false;
+ // Scan through the parents (bottom-to-top) and check if the selection is
+ // contained in a compound statement that's a body of a function/method
+ // declaration.
+ for (const auto &Parent : llvm::reverse(Parents)) {
+ const DynTypedNode &Node = Parent.get().Node;
+ if (const auto *D = Node.get<Decl>()) {
+ if (isFunctionLikeDeclaration(D))
+ return IsPrevCompound;
+ // Stop the search at any type declaration to avoid returning true for
+ // expressions in type declarations in functions, like:
+ // function foo() { struct X {
+ // int m = /*selection:*/ 1 + 2 /*selection end*/; }; };
+ if (isa<TypeDecl>(D))
+ return false;
+ }
+ IsPrevCompound = Node.get<CompoundStmt>() != nullptr;
+ }
+ return false;
+}
+
+const Decl *CodeRangeASTSelection::getFunctionLikeNearestParent() const {
+ for (const auto &Parent : llvm::reverse(Parents)) {
+ const DynTypedNode &Node = Parent.get().Node;
+ if (const auto *D = Node.get<Decl>()) {
+ if (isFunctionLikeDeclaration(D))
+ return D;
+ }
+ }
+ return nullptr;
+}
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
new file mode 100644
index 000000000000..c0232c5da442
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
@@ -0,0 +1,48 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
+
+using namespace clang;
+using namespace tooling;
+
+Expected<SelectedASTNode>
+ASTSelectionRequirement::evaluate(RefactoringRuleContext &Context) const {
+ // FIXME: Memoize so that selection is evaluated only once.
+ Expected<SourceRange> Range =
+ SourceRangeSelectionRequirement::evaluate(Context);
+ if (!Range)
+ return Range.takeError();
+
+ Optional<SelectedASTNode> Selection =
+ findSelectedASTNodes(Context.getASTContext(), *Range);
+ if (!Selection)
+ return Context.createDiagnosticError(
+ Range->getBegin(), diag::err_refactor_selection_invalid_ast);
+ return std::move(*Selection);
+}
+
+Expected<CodeRangeASTSelection> CodeRangeASTSelectionRequirement::evaluate(
+ RefactoringRuleContext &Context) const {
+ // FIXME: Memoize so that selection is evaluated only once.
+ Expected<SelectedASTNode> ASTSelection =
+ ASTSelectionRequirement::evaluate(Context);
+ if (!ASTSelection)
+ return ASTSelection.takeError();
+ std::unique_ptr<SelectedASTNode> StoredSelection =
+ llvm::make_unique<SelectedASTNode>(std::move(*ASTSelection));
+ Optional<CodeRangeASTSelection> CodeRange = CodeRangeASTSelection::create(
+ Context.getSelectionRange(), *StoredSelection);
+ if (!CodeRange)
+ return Context.createDiagnosticError(
+ Context.getSelectionRange().getBegin(),
+ diag::err_refactor_selection_invalid_ast);
+ Context.setASTSelection(std::move(StoredSelection));
+ return std::move(*CodeRange);
+}
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp
new file mode 100644
index 000000000000..e8b0fdbeb662
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp
@@ -0,0 +1,365 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/ReplacementsYaml.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <string>
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::AtomicChange)
+
+namespace {
+/// Helper to (de)serialize an AtomicChange since we don't have direct
+/// access to its data members.
+/// Data members of a normalized AtomicChange can be directly mapped from/to
+/// YAML string.
+struct NormalizedAtomicChange {
+ NormalizedAtomicChange() = default;
+
+ NormalizedAtomicChange(const llvm::yaml::IO &) {}
+
+ // This converts AtomicChange's internal implementation of the replacements
+ // set to a vector of replacements.
+ NormalizedAtomicChange(const llvm::yaml::IO &,
+ const clang::tooling::AtomicChange &E)
+ : Key(E.getKey()), FilePath(E.getFilePath()), Error(E.getError()),
+ InsertedHeaders(E.getInsertedHeaders()),
+ RemovedHeaders(E.getRemovedHeaders()),
+ Replaces(E.getReplacements().begin(), E.getReplacements().end()) {}
+
+ // This is not expected to be called but needed for template instantiation.
+ clang::tooling::AtomicChange denormalize(const llvm::yaml::IO &) {
+ llvm_unreachable("Do not convert YAML to AtomicChange directly with '>>'. "
+ "Use AtomicChange::convertFromYAML instead.");
+ }
+ std::string Key;
+ std::string FilePath;
+ std::string Error;
+ std::vector<std::string> InsertedHeaders;
+ std::vector<std::string> RemovedHeaders;
+ std::vector<clang::tooling::Replacement> Replaces;
+};
+} // anonymous namespace
+
+namespace llvm {
+namespace yaml {
+
+/// Specialized MappingTraits to describe how an AtomicChange is
+/// (de)serialized.
+template <> struct MappingTraits<NormalizedAtomicChange> {
+ static void mapping(IO &Io, NormalizedAtomicChange &Doc) {
+ Io.mapRequired("Key", Doc.Key);
+ Io.mapRequired("FilePath", Doc.FilePath);
+ Io.mapRequired("Error", Doc.Error);
+ Io.mapRequired("InsertedHeaders", Doc.InsertedHeaders);
+ Io.mapRequired("RemovedHeaders", Doc.RemovedHeaders);
+ Io.mapRequired("Replacements", Doc.Replaces);
+ }
+};
+
+/// Specialized MappingTraits to describe how an AtomicChange is
+/// (de)serialized.
+template <> struct MappingTraits<clang::tooling::AtomicChange> {
+ static void mapping(IO &Io, clang::tooling::AtomicChange &Doc) {
+ MappingNormalization<NormalizedAtomicChange, clang::tooling::AtomicChange>
+ Keys(Io, Doc);
+ Io.mapRequired("Key", Keys->Key);
+ Io.mapRequired("FilePath", Keys->FilePath);
+ Io.mapRequired("Error", Keys->Error);
+ Io.mapRequired("InsertedHeaders", Keys->InsertedHeaders);
+ Io.mapRequired("RemovedHeaders", Keys->RemovedHeaders);
+ Io.mapRequired("Replacements", Keys->Replaces);
+ }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+namespace clang {
+namespace tooling {
+namespace {
+
+// Returns true if there is any line that violates \p ColumnLimit in range
+// [Start, End].
+bool violatesColumnLimit(llvm::StringRef Code, unsigned ColumnLimit,
+ unsigned Start, unsigned End) {
+ auto StartPos = Code.rfind('\n', Start);
+ StartPos = (StartPos == llvm::StringRef::npos) ? 0 : StartPos + 1;
+
+ auto EndPos = Code.find("\n", End);
+ if (EndPos == llvm::StringRef::npos)
+ EndPos = Code.size();
+
+ llvm::SmallVector<llvm::StringRef, 8> Lines;
+ Code.substr(StartPos, EndPos - StartPos).split(Lines, '\n');
+ for (llvm::StringRef Line : Lines)
+ if (Line.size() > ColumnLimit)
+ return true;
+ return false;
+}
+
+std::vector<Range>
+getRangesForFormating(llvm::StringRef Code, unsigned ColumnLimit,
+ ApplyChangesSpec::FormatOption Format,
+ const clang::tooling::Replacements &Replaces) {
+ // kNone suppresses formatting entirely.
+ if (Format == ApplyChangesSpec::kNone)
+ return {};
+ std::vector<clang::tooling::Range> Ranges;
+ // This works assuming that replacements are ordered by offset.
+ // FIXME: use `getAffectedRanges()` to calculate when it does not include '\n'
+ // at the end of an insertion in affected ranges.
+ int Offset = 0;
+ for (const clang::tooling::Replacement &R : Replaces) {
+ int Start = R.getOffset() + Offset;
+ int End = Start + R.getReplacementText().size();
+ if (!R.getReplacementText().empty() &&
+ R.getReplacementText().back() == '\n' && R.getLength() == 0 &&
+ R.getOffset() > 0 && R.getOffset() <= Code.size() &&
+ Code[R.getOffset() - 1] == '\n')
+ // If we are inserting at the start of a line and the replacement ends in
+ // a newline, we don't need to format the subsequent line.
+ --End;
+ Offset += R.getReplacementText().size() - R.getLength();
+
+ if (Format == ApplyChangesSpec::kAll ||
+ violatesColumnLimit(Code, ColumnLimit, Start, End))
+ Ranges.emplace_back(Start, End - Start);
+ }
+ return Ranges;
+}
+
+inline llvm::Error make_string_error(const llvm::Twine &Message) {
+ return llvm::make_error<llvm::StringError>(Message,
+ llvm::inconvertibleErrorCode());
+}
+
+// Creates replacements for inserting/deleting #include headers.
+llvm::Expected<Replacements>
+createReplacementsForHeaders(llvm::StringRef FilePath, llvm::StringRef Code,
+ llvm::ArrayRef<AtomicChange> Changes,
+ const format::FormatStyle &Style) {
+ // Create header insertion/deletion replacements to be cleaned up
+ // (i.e. converted to real insertion/deletion replacements).
+ Replacements HeaderReplacements;
+ for (const auto &Change : Changes) {
+ for (llvm::StringRef Header : Change.getInsertedHeaders()) {
+ std::string EscapedHeader =
+ Header.startswith("<") || Header.startswith("\"")
+ ? Header.str()
+ : ("\"" + Header + "\"").str();
+ std::string ReplacementText = "#include " + EscapedHeader;
+ // Offset UINT_MAX and length 0 indicate that the replacement is a header
+ // insertion.
+ llvm::Error Err = HeaderReplacements.add(
+ tooling::Replacement(FilePath, UINT_MAX, 0, ReplacementText));
+ if (Err)
+ return std::move(Err);
+ }
+ for (const std::string &Header : Change.getRemovedHeaders()) {
+ // Offset UINT_MAX and length 1 indicate that the replacement is a header
+ // deletion.
+ llvm::Error Err =
+ HeaderReplacements.add(Replacement(FilePath, UINT_MAX, 1, Header));
+ if (Err)
+ return std::move(Err);
+ }
+ }
+
+ // cleanupAroundReplacements() converts header insertions/deletions into
+ // actual replacements that add/remove headers at the right location.
+ return clang::format::cleanupAroundReplacements(Code, HeaderReplacements,
+ Style);
+}
+
+// Combine replacements in all Changes as a `Replacements`. This ignores the
+// file path in all replacements and replaces them with \p FilePath.
+llvm::Expected<Replacements>
+combineReplacementsInChanges(llvm::StringRef FilePath,
+ llvm::ArrayRef<AtomicChange> Changes) {
+ Replacements Replaces;
+ for (const auto &Change : Changes)
+ for (const auto &R : Change.getReplacements())
+ if (auto Err = Replaces.add(Replacement(
+ FilePath, R.getOffset(), R.getLength(), R.getReplacementText())))
+ return std::move(Err);
+ return Replaces;
+}
+
+} // end namespace
+
+AtomicChange::AtomicChange(const SourceManager &SM,
+ SourceLocation KeyPosition) {
+ const FullSourceLoc FullKeyPosition(KeyPosition, SM);
+ std::pair<FileID, unsigned> FileIDAndOffset =
+ FullKeyPosition.getSpellingLoc().getDecomposedLoc();
+ const FileEntry *FE = SM.getFileEntryForID(FileIDAndOffset.first);
+ assert(FE && "Cannot create AtomicChange with invalid location.");
+ FilePath = FE->getName();
+ Key = FilePath + ":" + std::to_string(FileIDAndOffset.second);
+}
+
+AtomicChange::AtomicChange(std::string Key, std::string FilePath,
+ std::string Error,
+ std::vector<std::string> InsertedHeaders,
+ std::vector<std::string> RemovedHeaders,
+ clang::tooling::Replacements Replaces)
+ : Key(std::move(Key)), FilePath(std::move(FilePath)),
+ Error(std::move(Error)), InsertedHeaders(std::move(InsertedHeaders)),
+ RemovedHeaders(std::move(RemovedHeaders)), Replaces(std::move(Replaces)) {
+}
+
+bool AtomicChange::operator==(const AtomicChange &Other) const {
+ if (Key != Other.Key || FilePath != Other.FilePath || Error != Other.Error)
+ return false;
+ if (!(Replaces == Other.Replaces))
+ return false;
+ // FXIME: Compare header insertions/removals.
+ return true;
+}
+
+std::string AtomicChange::toYAMLString() {
+ std::string YamlContent;
+ llvm::raw_string_ostream YamlContentStream(YamlContent);
+
+ llvm::yaml::Output YAML(YamlContentStream);
+ YAML << *this;
+ YamlContentStream.flush();
+ return YamlContent;
+}
+
+AtomicChange AtomicChange::convertFromYAML(llvm::StringRef YAMLContent) {
+ NormalizedAtomicChange NE;
+ llvm::yaml::Input YAML(YAMLContent);
+ YAML >> NE;
+ AtomicChange E(NE.Key, NE.FilePath, NE.Error, NE.InsertedHeaders,
+ NE.RemovedHeaders, tooling::Replacements());
+ for (const auto &R : NE.Replaces) {
+ llvm::Error Err = E.Replaces.add(R);
+ if (Err)
+ llvm_unreachable(
+ "Failed to add replacement when Converting YAML to AtomicChange.");
+ llvm::consumeError(std::move(Err));
+ }
+ return E;
+}
+
+llvm::Error AtomicChange::replace(const SourceManager &SM,
+ const CharSourceRange &Range,
+ llvm::StringRef ReplacementText) {
+ return Replaces.add(Replacement(SM, Range, ReplacementText));
+}
+
+llvm::Error AtomicChange::replace(const SourceManager &SM, SourceLocation Loc,
+ unsigned Length, llvm::StringRef Text) {
+ return Replaces.add(Replacement(SM, Loc, Length, Text));
+}
+
+llvm::Error AtomicChange::insert(const SourceManager &SM, SourceLocation Loc,
+ llvm::StringRef Text, bool InsertAfter) {
+ if (Text.empty())
+ return llvm::Error::success();
+ Replacement R(SM, Loc, 0, Text);
+ llvm::Error Err = Replaces.add(R);
+ if (Err) {
+ return llvm::handleErrors(
+ std::move(Err), [&](const ReplacementError &RE) -> llvm::Error {
+ if (RE.get() != replacement_error::insert_conflict)
+ return llvm::make_error<ReplacementError>(RE);
+ unsigned NewOffset = Replaces.getShiftedCodePosition(R.getOffset());
+ if (!InsertAfter)
+ NewOffset -=
+ RE.getExistingReplacement()->getReplacementText().size();
+ Replacement NewR(R.getFilePath(), NewOffset, 0, Text);
+ Replaces = Replaces.merge(Replacements(NewR));
+ return llvm::Error::success();
+ });
+ }
+ return llvm::Error::success();
+}
+
+void AtomicChange::addHeader(llvm::StringRef Header) {
+ InsertedHeaders.push_back(Header);
+}
+
+void AtomicChange::removeHeader(llvm::StringRef Header) {
+ RemovedHeaders.push_back(Header);
+}
+
+llvm::Expected<std::string>
+applyAtomicChanges(llvm::StringRef FilePath, llvm::StringRef Code,
+ llvm::ArrayRef<AtomicChange> Changes,
+ const ApplyChangesSpec &Spec) {
+ llvm::Expected<Replacements> HeaderReplacements =
+ createReplacementsForHeaders(FilePath, Code, Changes, Spec.Style);
+ if (!HeaderReplacements)
+ return make_string_error(
+ "Failed to create replacements for header changes: " +
+ llvm::toString(HeaderReplacements.takeError()));
+
+ llvm::Expected<Replacements> Replaces =
+ combineReplacementsInChanges(FilePath, Changes);
+ if (!Replaces)
+ return make_string_error("Failed to combine replacements in all changes: " +
+ llvm::toString(Replaces.takeError()));
+
+ Replacements AllReplaces = std::move(*Replaces);
+ for (const auto &R : *HeaderReplacements) {
+ llvm::Error Err = AllReplaces.add(R);
+ if (Err)
+ return make_string_error(
+ "Failed to combine existing replacements with header replacements: " +
+ llvm::toString(std::move(Err)));
+ }
+
+ if (Spec.Cleanup) {
+ llvm::Expected<Replacements> CleanReplaces =
+ format::cleanupAroundReplacements(Code, AllReplaces, Spec.Style);
+ if (!CleanReplaces)
+ return make_string_error("Failed to cleanup around replacements: " +
+ llvm::toString(CleanReplaces.takeError()));
+ AllReplaces = std::move(*CleanReplaces);
+ }
+
+ // Apply all replacements.
+ llvm::Expected<std::string> ChangedCode =
+ applyAllReplacements(Code, AllReplaces);
+ if (!ChangedCode)
+ return make_string_error("Failed to apply all replacements: " +
+ llvm::toString(ChangedCode.takeError()));
+
+ // Sort inserted headers. This is done even if other formatting is turned off
+ // as incorrectly sorted headers are always just wrong, it's not a matter of
+ // taste.
+ Replacements HeaderSortingReplacements = format::sortIncludes(
+ Spec.Style, *ChangedCode, AllReplaces.getAffectedRanges(), FilePath);
+ ChangedCode = applyAllReplacements(*ChangedCode, HeaderSortingReplacements);
+ if (!ChangedCode)
+ return make_string_error(
+ "Failed to apply replacements for sorting includes: " +
+ llvm::toString(ChangedCode.takeError()));
+
+ AllReplaces = AllReplaces.merge(HeaderSortingReplacements);
+
+ std::vector<Range> FormatRanges = getRangesForFormating(
+ *ChangedCode, Spec.Style.ColumnLimit, Spec.Format, AllReplaces);
+ if (!FormatRanges.empty()) {
+ Replacements FormatReplacements =
+ format::reformat(Spec.Style, *ChangedCode, FormatRanges, FilePath);
+ ChangedCode = applyAllReplacements(*ChangedCode, FormatReplacements);
+ if (!ChangedCode)
+ return make_string_error(
+ "Failed to apply replacements for formatting changed code: " +
+ llvm::toString(ChangedCode.takeError()));
+ }
+ return ChangedCode;
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/Extract.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/Extract.cpp
new file mode 100644
index 000000000000..7a741bdb2e91
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/Extract.cpp
@@ -0,0 +1,199 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implements the "extract" refactoring that can pull code into
+/// new functions, methods or declare new variables.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Extract/Extract.h"
+#include "SourceExtraction.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+/// Returns true if \c E is a simple literal or a reference expression that
+/// should not be extracted.
+bool isSimpleExpression(const Expr *E) {
+ if (!E)
+ return false;
+ switch (E->IgnoreParenCasts()->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ case Stmt::PredefinedExprClass:
+ case Stmt::IntegerLiteralClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::StringLiteralClass:
+ return true;
+ default:
+ return false;
+ }
+}
+
+SourceLocation computeFunctionExtractionLocation(const Decl *D) {
+ if (isa<CXXMethodDecl>(D)) {
+ // Code from method that is defined in class body should be extracted to a
+ // function defined just before the class.
+ while (const auto *RD = dyn_cast<CXXRecordDecl>(D->getLexicalDeclContext()))
+ D = RD;
+ }
+ return D->getBeginLoc();
+}
+
+} // end anonymous namespace
+
+const RefactoringDescriptor &ExtractFunction::describe() {
+ static const RefactoringDescriptor Descriptor = {
+ "extract-function",
+ "Extract Function",
+ "(WIP action; use with caution!) Extracts code into a new function",
+ };
+ return Descriptor;
+}
+
+Expected<ExtractFunction>
+ExtractFunction::initiate(RefactoringRuleContext &Context,
+ CodeRangeASTSelection Code,
+ Optional<std::string> DeclName) {
+ // We would like to extract code out of functions/methods/blocks.
+ // Prohibit extraction from things like global variable / field
+ // initializers and other top-level expressions.
+ if (!Code.isInFunctionLikeBodyOfCode())
+ return Context.createDiagnosticError(
+ diag::err_refactor_code_outside_of_function);
+
+ if (Code.size() == 1) {
+ // Avoid extraction of simple literals and references.
+ if (isSimpleExpression(dyn_cast<Expr>(Code[0])))
+ return Context.createDiagnosticError(
+ diag::err_refactor_extract_simple_expression);
+
+ // Property setters can't be extracted.
+ if (const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(Code[0])) {
+ if (!PRE->isMessagingGetter())
+ return Context.createDiagnosticError(
+ diag::err_refactor_extract_prohibited_expression);
+ }
+ }
+
+ return ExtractFunction(std::move(Code), DeclName);
+}
+
+// FIXME: Support C++ method extraction.
+// FIXME: Support Objective-C method extraction.
+Expected<AtomicChanges>
+ExtractFunction::createSourceReplacements(RefactoringRuleContext &Context) {
+ const Decl *ParentDecl = Code.getFunctionLikeNearestParent();
+ assert(ParentDecl && "missing parent");
+
+ // Compute the source range of the code that should be extracted.
+ SourceRange ExtractedRange(Code[0]->getBeginLoc(),
+ Code[Code.size() - 1]->getEndLoc());
+ // FIXME (Alex L): Add code that accounts for macro locations.
+
+ ASTContext &AST = Context.getASTContext();
+ SourceManager &SM = AST.getSourceManager();
+ const LangOptions &LangOpts = AST.getLangOpts();
+ Rewriter ExtractedCodeRewriter(SM, LangOpts);
+
+ // FIXME: Capture used variables.
+
+ // Compute the return type.
+ QualType ReturnType = AST.VoidTy;
+ // FIXME (Alex L): Account for the return statement in extracted code.
+ // FIXME (Alex L): Check for lexical expression instead.
+ bool IsExpr = Code.size() == 1 && isa<Expr>(Code[0]);
+ if (IsExpr) {
+ // FIXME (Alex L): Get a more user-friendly type if needed.
+ ReturnType = cast<Expr>(Code[0])->getType();
+ }
+
+ // FIXME: Rewrite the extracted code performing any required adjustments.
+
+ // FIXME: Capture any field if necessary (method -> function extraction).
+
+ // FIXME: Sort captured variables by name.
+
+ // FIXME: Capture 'this' / 'self' if necessary.
+
+ // FIXME: Compute the actual parameter types.
+
+ // Compute the location of the extracted declaration.
+ SourceLocation ExtractedDeclLocation =
+ computeFunctionExtractionLocation(ParentDecl);
+ // FIXME: Adjust the location to account for any preceding comments.
+
+ // FIXME: Adjust with PP awareness like in Sema to get correct 'bool'
+ // treatment.
+ PrintingPolicy PP = AST.getPrintingPolicy();
+ // FIXME: PP.UseStdFunctionForLambda = true;
+ PP.SuppressStrongLifetime = true;
+ PP.SuppressLifetimeQualifiers = true;
+ PP.SuppressUnwrittenScope = true;
+
+ ExtractionSemicolonPolicy Semicolons = ExtractionSemicolonPolicy::compute(
+ Code[Code.size() - 1], ExtractedRange, SM, LangOpts);
+ AtomicChange Change(SM, ExtractedDeclLocation);
+ // Create the replacement for the extracted declaration.
+ {
+ std::string ExtractedCode;
+ llvm::raw_string_ostream OS(ExtractedCode);
+ // FIXME: Use 'inline' in header.
+ OS << "static ";
+ ReturnType.print(OS, PP, DeclName);
+ OS << '(';
+ // FIXME: Arguments.
+ OS << ')';
+
+ // Function body.
+ OS << " {\n";
+ if (IsExpr && !ReturnType->isVoidType())
+ OS << "return ";
+ OS << ExtractedCodeRewriter.getRewrittenText(ExtractedRange);
+ if (Semicolons.isNeededInExtractedFunction())
+ OS << ';';
+ OS << "\n}\n\n";
+ auto Err = Change.insert(SM, ExtractedDeclLocation, OS.str());
+ if (Err)
+ return std::move(Err);
+ }
+
+ // Create the replacement for the call to the extracted declaration.
+ {
+ std::string ReplacedCode;
+ llvm::raw_string_ostream OS(ReplacedCode);
+
+ OS << DeclName << '(';
+ // FIXME: Forward arguments.
+ OS << ')';
+ if (Semicolons.isNeededInOriginalFunction())
+ OS << ';';
+
+ auto Err = Change.replace(
+ SM, CharSourceRange::getTokenRange(ExtractedRange), OS.str());
+ if (Err)
+ return std::move(Err);
+ }
+
+ // FIXME: Add support for assocciated symbol location to AtomicChange to mark
+ // the ranges of the name of the extracted declaration.
+ return AtomicChanges{std::move(Change)};
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
new file mode 100644
index 000000000000..7fd8cc2d3c7f
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
@@ -0,0 +1,112 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SourceExtraction.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang;
+
+namespace {
+
+/// Returns true if the token at the given location is a semicolon.
+bool isSemicolonAtLocation(SourceLocation TokenLoc, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ return Lexer::getSourceText(
+ CharSourceRange::getTokenRange(TokenLoc, TokenLoc), SM,
+ LangOpts) == ";";
+}
+
+/// Returns true if there should be a semicolon after the given statement.
+bool isSemicolonRequiredAfter(const Stmt *S) {
+ if (isa<CompoundStmt>(S))
+ return false;
+ if (const auto *If = dyn_cast<IfStmt>(S))
+ return isSemicolonRequiredAfter(If->getElse() ? If->getElse()
+ : If->getThen());
+ if (const auto *While = dyn_cast<WhileStmt>(S))
+ return isSemicolonRequiredAfter(While->getBody());
+ if (const auto *For = dyn_cast<ForStmt>(S))
+ return isSemicolonRequiredAfter(For->getBody());
+ if (const auto *CXXFor = dyn_cast<CXXForRangeStmt>(S))
+ return isSemicolonRequiredAfter(CXXFor->getBody());
+ if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(S))
+ return isSemicolonRequiredAfter(ObjCFor->getBody());
+ switch (S->getStmtClass()) {
+ case Stmt::SwitchStmtClass:
+ case Stmt::CXXTryStmtClass:
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ case Stmt::ObjCAutoreleasePoolStmtClass:
+ case Stmt::ObjCAtTryStmtClass:
+ return false;
+ default:
+ return true;
+ }
+}
+
+/// Returns true if the two source locations are on the same line.
+bool areOnSameLine(SourceLocation Loc1, SourceLocation Loc2,
+ const SourceManager &SM) {
+ return !Loc1.isMacroID() && !Loc2.isMacroID() &&
+ SM.getSpellingLineNumber(Loc1) == SM.getSpellingLineNumber(Loc2);
+}
+
+} // end anonymous namespace
+
+namespace clang {
+namespace tooling {
+
+ExtractionSemicolonPolicy
+ExtractionSemicolonPolicy::compute(const Stmt *S, SourceRange &ExtractedRange,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ auto neededInExtractedFunction = []() {
+ return ExtractionSemicolonPolicy(true, false);
+ };
+ auto neededInOriginalFunction = []() {
+ return ExtractionSemicolonPolicy(false, true);
+ };
+
+ /// The extracted expression should be terminated with a ';'. The call to
+ /// the extracted function will replace this expression, so it won't need
+ /// a terminating ';'.
+ if (isa<Expr>(S))
+ return neededInExtractedFunction();
+
+ /// Some statements don't need to be terminated with ';'. The call to the
+ /// extracted function will be a standalone statement, so it should be
+ /// terminated with a ';'.
+ bool NeedsSemi = isSemicolonRequiredAfter(S);
+ if (!NeedsSemi)
+ return neededInOriginalFunction();
+
+ /// Some statements might end at ';'. The extraction will move that ';', so
+ /// the call to the extracted function should be terminated with a ';'.
+ SourceLocation End = ExtractedRange.getEnd();
+ if (isSemicolonAtLocation(End, SM, LangOpts))
+ return neededInOriginalFunction();
+
+ /// Other statements should generally have a trailing ';'. We can try to find
+ /// it and move it together it with the extracted code.
+ Optional<Token> NextToken = Lexer::findNextToken(End, SM, LangOpts);
+ if (NextToken && NextToken->is(tok::semi) &&
+ areOnSameLine(NextToken->getLocation(), End, SM)) {
+ ExtractedRange.setEnd(NextToken->getLocation());
+ return neededInOriginalFunction();
+ }
+
+ /// Otherwise insert semicolons in both places.
+ return ExtractionSemicolonPolicy(true, true);
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.h b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.h
new file mode 100644
index 000000000000..4b4bd8b477ff
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.h
@@ -0,0 +1,52 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
+#define LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+
+class LangOptions;
+class SourceManager;
+class SourceRange;
+class Stmt;
+
+namespace tooling {
+
+/// Determines which semicolons should be inserted during extraction.
+class ExtractionSemicolonPolicy {
+public:
+ bool isNeededInExtractedFunction() const {
+ return IsNeededInExtractedFunction;
+ }
+
+ bool isNeededInOriginalFunction() const { return IsNeededInOriginalFunction; }
+
+ /// Returns the semicolon insertion policy that is needed for extraction of
+ /// the given statement from the given source range.
+ static ExtractionSemicolonPolicy compute(const Stmt *S,
+ SourceRange &ExtractedRange,
+ const SourceManager &SM,
+ const LangOptions &LangOpts);
+
+private:
+ ExtractionSemicolonPolicy(bool IsNeededInExtractedFunction,
+ bool IsNeededInOriginalFunction)
+ : IsNeededInExtractedFunction(IsNeededInExtractedFunction),
+ IsNeededInOriginalFunction(IsNeededInOriginalFunction) {}
+ bool IsNeededInExtractedFunction;
+ bool IsNeededInOriginalFunction;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/RefactoringActions.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/RefactoringActions.cpp
new file mode 100644
index 000000000000..37a1639cb446
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/RefactoringActions.cpp
@@ -0,0 +1,114 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Extract/Extract.h"
+#include "clang/Tooling/Refactoring/RefactoringAction.h"
+#include "clang/Tooling/Refactoring/RefactoringOptions.h"
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+class DeclNameOption final : public OptionalRefactoringOption<std::string> {
+public:
+ StringRef getName() const { return "name"; }
+ StringRef getDescription() const {
+ return "Name of the extracted declaration";
+ }
+};
+
+// FIXME: Rewrite the Actions to avoid duplication of descriptions/names with
+// rules.
+class ExtractRefactoring final : public RefactoringAction {
+public:
+ StringRef getCommand() const override { return "extract"; }
+
+ StringRef getDescription() const override {
+ return "(WIP action; use with caution!) Extracts code into a new function";
+ }
+
+ /// Returns a set of refactoring actions rules that are defined by this
+ /// action.
+ RefactoringActionRules createActionRules() const override {
+ RefactoringActionRules Rules;
+ Rules.push_back(createRefactoringActionRule<ExtractFunction>(
+ CodeRangeASTSelectionRequirement(),
+ OptionRequirement<DeclNameOption>()));
+ return Rules;
+ }
+};
+
+class OldQualifiedNameOption : public RequiredRefactoringOption<std::string> {
+public:
+ StringRef getName() const override { return "old-qualified-name"; }
+ StringRef getDescription() const override {
+ return "The old qualified name to be renamed";
+ }
+};
+
+class NewQualifiedNameOption : public RequiredRefactoringOption<std::string> {
+public:
+ StringRef getName() const override { return "new-qualified-name"; }
+ StringRef getDescription() const override {
+ return "The new qualified name to change the symbol to";
+ }
+};
+
+class NewNameOption : public RequiredRefactoringOption<std::string> {
+public:
+ StringRef getName() const override { return "new-name"; }
+ StringRef getDescription() const override {
+ return "The new name to change the symbol to";
+ }
+};
+
+// FIXME: Rewrite the Actions to avoid duplication of descriptions/names with
+// rules.
+class LocalRename final : public RefactoringAction {
+public:
+ StringRef getCommand() const override { return "local-rename"; }
+
+ StringRef getDescription() const override {
+ return "Finds and renames symbols in code with no indexer support";
+ }
+
+ /// Returns a set of refactoring actions rules that are defined by this
+ /// action.
+ RefactoringActionRules createActionRules() const override {
+ RefactoringActionRules Rules;
+ Rules.push_back(createRefactoringActionRule<RenameOccurrences>(
+ SourceRangeSelectionRequirement(), OptionRequirement<NewNameOption>()));
+ // FIXME: Use NewNameOption.
+ Rules.push_back(createRefactoringActionRule<QualifiedRenameRule>(
+ OptionRequirement<OldQualifiedNameOption>(),
+ OptionRequirement<NewQualifiedNameOption>()));
+ return Rules;
+ }
+};
+
+} // end anonymous namespace
+
+std::vector<std::unique_ptr<RefactoringAction>> createRefactoringActions() {
+ std::vector<std::unique_ptr<RefactoringAction>> Actions;
+
+ Actions.push_back(llvm::make_unique<LocalRename>());
+ Actions.push_back(llvm::make_unique<ExtractRefactoring>());
+
+ return Actions;
+}
+
+RefactoringActionRules RefactoringAction::createActiveActionRules() {
+ // FIXME: Filter out rules that are not supported by a particular client.
+ return createActionRules();
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
new file mode 100644
index 000000000000..44ffae90efa7
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
@@ -0,0 +1,277 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Provides an action to rename every symbol at a point.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/RefactoringAction.h"
+#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
+#include "clang/Tooling/Refactoring/RefactoringOptions.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
+#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+Expected<SymbolOccurrences>
+findSymbolOccurrences(const NamedDecl *ND, RefactoringRuleContext &Context) {
+ std::vector<std::string> USRs =
+ getUSRsForDeclaration(ND, Context.getASTContext());
+ std::string PrevName = ND->getNameAsString();
+ return getOccurrencesOfUSRs(USRs, PrevName,
+ Context.getASTContext().getTranslationUnitDecl());
+}
+
+} // end anonymous namespace
+
+const RefactoringDescriptor &RenameOccurrences::describe() {
+ static const RefactoringDescriptor Descriptor = {
+ "local-rename",
+ "Rename",
+ "Finds and renames symbols in code with no indexer support",
+ };
+ return Descriptor;
+}
+
+Expected<RenameOccurrences>
+RenameOccurrences::initiate(RefactoringRuleContext &Context,
+ SourceRange SelectionRange, std::string NewName) {
+ const NamedDecl *ND =
+ getNamedDeclAt(Context.getASTContext(), SelectionRange.getBegin());
+ if (!ND)
+ return Context.createDiagnosticError(
+ SelectionRange.getBegin(), diag::err_refactor_selection_no_symbol);
+ return RenameOccurrences(getCanonicalSymbolDeclaration(ND),
+ std::move(NewName));
+}
+
+Expected<AtomicChanges>
+RenameOccurrences::createSourceReplacements(RefactoringRuleContext &Context) {
+ Expected<SymbolOccurrences> Occurrences = findSymbolOccurrences(ND, Context);
+ if (!Occurrences)
+ return Occurrences.takeError();
+ // FIXME: Verify that the new name is valid.
+ SymbolName Name(NewName);
+ return createRenameReplacements(
+ *Occurrences, Context.getASTContext().getSourceManager(), Name);
+}
+
+Expected<QualifiedRenameRule>
+QualifiedRenameRule::initiate(RefactoringRuleContext &Context,
+ std::string OldQualifiedName,
+ std::string NewQualifiedName) {
+ const NamedDecl *ND =
+ getNamedDeclFor(Context.getASTContext(), OldQualifiedName);
+ if (!ND)
+ return llvm::make_error<llvm::StringError>("Could not find symbol " +
+ OldQualifiedName,
+ llvm::errc::invalid_argument);
+ return QualifiedRenameRule(ND, std::move(NewQualifiedName));
+}
+
+const RefactoringDescriptor &QualifiedRenameRule::describe() {
+ static const RefactoringDescriptor Descriptor = {
+ /*Name=*/"local-qualified-rename",
+ /*Title=*/"Qualified Rename",
+ /*Description=*/
+ R"(Finds and renames qualified symbols in code within a translation unit.
+It is used to move/rename a symbol to a new namespace/name:
+ * Supported symbols: classes, class members, functions, enums, and type alias.
+ * Renames all symbol occurrences from the old qualified name to the new
+ qualified name. All symbol references will be correctly qualified; For
+ symbol definitions, only name will be changed.
+For example, rename "A::Foo" to "B::Bar":
+ Old code:
+ namespace foo {
+ class A {};
+ }
+
+ namespace bar {
+ void f(foo::A a) {}
+ }
+
+ New code after rename:
+ namespace foo {
+ class B {};
+ }
+
+ namespace bar {
+ void f(B b) {}
+ })"
+ };
+ return Descriptor;
+}
+
+Expected<AtomicChanges>
+QualifiedRenameRule::createSourceReplacements(RefactoringRuleContext &Context) {
+ auto USRs = getUSRsForDeclaration(ND, Context.getASTContext());
+ assert(!USRs.empty());
+ return tooling::createRenameAtomicChanges(
+ USRs, NewQualifiedName, Context.getASTContext().getTranslationUnitDecl());
+}
+
+Expected<std::vector<AtomicChange>>
+createRenameReplacements(const SymbolOccurrences &Occurrences,
+ const SourceManager &SM, const SymbolName &NewName) {
+ // FIXME: A true local rename can use just one AtomicChange.
+ std::vector<AtomicChange> Changes;
+ for (const auto &Occurrence : Occurrences) {
+ ArrayRef<SourceRange> Ranges = Occurrence.getNameRanges();
+ assert(NewName.getNamePieces().size() == Ranges.size() &&
+ "Mismatching number of ranges and name pieces");
+ AtomicChange Change(SM, Ranges[0].getBegin());
+ for (const auto &Range : llvm::enumerate(Ranges)) {
+ auto Error =
+ Change.replace(SM, CharSourceRange::getCharRange(Range.value()),
+ NewName.getNamePieces()[Range.index()]);
+ if (Error)
+ return std::move(Error);
+ }
+ Changes.push_back(std::move(Change));
+ }
+ return std::move(Changes);
+}
+
+/// Takes each atomic change and inserts its replacements into the set of
+/// replacements that belong to the appropriate file.
+static void convertChangesToFileReplacements(
+ ArrayRef<AtomicChange> AtomicChanges,
+ std::map<std::string, tooling::Replacements> *FileToReplaces) {
+ for (const auto &AtomicChange : AtomicChanges) {
+ for (const auto &Replace : AtomicChange.getReplacements()) {
+ llvm::Error Err = (*FileToReplaces)[Replace.getFilePath()].add(Replace);
+ if (Err) {
+ llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+ }
+ }
+}
+
+class RenamingASTConsumer : public ASTConsumer {
+public:
+ RenamingASTConsumer(
+ const std::vector<std::string> &NewNames,
+ const std::vector<std::string> &PrevNames,
+ const std::vector<std::vector<std::string>> &USRList,
+ std::map<std::string, tooling::Replacements> &FileToReplaces,
+ bool PrintLocations)
+ : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),
+ FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {}
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ for (unsigned I = 0; I < NewNames.size(); ++I) {
+ // If the previous name was not found, ignore this rename request.
+ if (PrevNames[I].empty())
+ continue;
+
+ HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]);
+ }
+ }
+
+ void HandleOneRename(ASTContext &Context, const std::string &NewName,
+ const std::string &PrevName,
+ const std::vector<std::string> &USRs) {
+ const SourceManager &SourceMgr = Context.getSourceManager();
+
+ SymbolOccurrences Occurrences = tooling::getOccurrencesOfUSRs(
+ USRs, PrevName, Context.getTranslationUnitDecl());
+ if (PrintLocations) {
+ for (const auto &Occurrence : Occurrences) {
+ FullSourceLoc FullLoc(Occurrence.getNameRanges()[0].getBegin(),
+ SourceMgr);
+ errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(FullLoc)
+ << ":" << FullLoc.getSpellingLineNumber() << ":"
+ << FullLoc.getSpellingColumnNumber() << "\n";
+ }
+ }
+ // FIXME: Support multi-piece names.
+ // FIXME: better error handling (propagate error out).
+ SymbolName NewNameRef(NewName);
+ Expected<std::vector<AtomicChange>> Change =
+ createRenameReplacements(Occurrences, SourceMgr, NewNameRef);
+ if (!Change) {
+ llvm::errs() << "Failed to create renaming replacements for '" << PrevName
+ << "'! " << llvm::toString(Change.takeError()) << "\n";
+ return;
+ }
+ convertChangesToFileReplacements(*Change, &FileToReplaces);
+ }
+
+private:
+ const std::vector<std::string> &NewNames, &PrevNames;
+ const std::vector<std::vector<std::string>> &USRList;
+ std::map<std::string, tooling::Replacements> &FileToReplaces;
+ bool PrintLocations;
+};
+
+// A renamer to rename symbols which are identified by a give USRList to
+// new name.
+//
+// FIXME: Merge with the above RenamingASTConsumer.
+class USRSymbolRenamer : public ASTConsumer {
+public:
+ USRSymbolRenamer(const std::vector<std::string> &NewNames,
+ const std::vector<std::vector<std::string>> &USRList,
+ std::map<std::string, tooling::Replacements> &FileToReplaces)
+ : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) {
+ assert(USRList.size() == NewNames.size());
+ }
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ for (unsigned I = 0; I < NewNames.size(); ++I) {
+ // FIXME: Apply AtomicChanges directly once the refactoring APIs are
+ // ready.
+ auto AtomicChanges = tooling::createRenameAtomicChanges(
+ USRList[I], NewNames[I], Context.getTranslationUnitDecl());
+ convertChangesToFileReplacements(AtomicChanges, &FileToReplaces);
+ }
+ }
+
+private:
+ const std::vector<std::string> &NewNames;
+ const std::vector<std::vector<std::string>> &USRList;
+ std::map<std::string, tooling::Replacements> &FileToReplaces;
+};
+
+std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() {
+ return llvm::make_unique<RenamingASTConsumer>(NewNames, PrevNames, USRList,
+ FileToReplaces, PrintLocations);
+}
+
+std::unique_ptr<ASTConsumer> QualifiedRenamingAction::newASTConsumer() {
+ return llvm::make_unique<USRSymbolRenamer>(NewNames, USRList, FileToReplaces);
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
new file mode 100644
index 000000000000..ea64b2c1aa8c
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
@@ -0,0 +1,37 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace clang;
+using namespace tooling;
+
+SymbolOccurrence::SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind,
+ ArrayRef<SourceLocation> Locations)
+ : Kind(Kind) {
+ ArrayRef<std::string> NamePieces = Name.getNamePieces();
+ assert(Locations.size() == NamePieces.size() &&
+ "mismatching number of locations and lengths");
+ assert(!Locations.empty() && "no locations");
+ if (Locations.size() == 1) {
+ RangeOrNumRanges = SourceRange(
+ Locations[0], Locations[0].getLocWithOffset(NamePieces[0].size()));
+ return;
+ }
+ MultipleRanges = llvm::make_unique<SourceRange[]>(Locations.size());
+ RangeOrNumRanges.setBegin(
+ SourceLocation::getFromRawEncoding(Locations.size()));
+ for (const auto &Loc : llvm::enumerate(Locations)) {
+ MultipleRanges[Loc.index()] = SourceRange(
+ Loc.value(),
+ Loc.value().getLocWithOffset(NamePieces[Loc.index()].size()));
+ }
+}
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
new file mode 100644
index 000000000000..4ed805fd504c
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
@@ -0,0 +1,146 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file Implements a recursive AST visitor that finds the USR of a symbol at a
+/// point.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Index/USRGeneration.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+/// Recursively visits each AST node to find the symbol underneath the cursor.
+class NamedDeclOccurrenceFindingVisitor
+ : public RecursiveSymbolVisitor<NamedDeclOccurrenceFindingVisitor> {
+public:
+ // Finds the NamedDecl at a point in the source.
+ // \param Point the location in the source to search for the NamedDecl.
+ explicit NamedDeclOccurrenceFindingVisitor(const SourceLocation Point,
+ const ASTContext &Context)
+ : RecursiveSymbolVisitor(Context.getSourceManager(),
+ Context.getLangOpts()),
+ Point(Point), Context(Context) {}
+
+ bool visitSymbolOccurrence(const NamedDecl *ND,
+ ArrayRef<SourceRange> NameRanges) {
+ if (!ND)
+ return true;
+ for (const auto &Range : NameRanges) {
+ SourceLocation Start = Range.getBegin();
+ SourceLocation End = Range.getEnd();
+ if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
+ !End.isFileID() || !isPointWithin(Start, End))
+ return true;
+ }
+ Result = ND;
+ return false;
+ }
+
+ const NamedDecl *getNamedDecl() const { return Result; }
+
+private:
+ // Determines if the Point is within Start and End.
+ bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
+ // FIXME: Add tests for Point == End.
+ return Point == Start || Point == End ||
+ (Context.getSourceManager().isBeforeInTranslationUnit(Start,
+ Point) &&
+ Context.getSourceManager().isBeforeInTranslationUnit(Point, End));
+ }
+
+ const NamedDecl *Result = nullptr;
+ const SourceLocation Point; // The location to find the NamedDecl.
+ const ASTContext &Context;
+};
+
+} // end anonymous namespace
+
+const NamedDecl *getNamedDeclAt(const ASTContext &Context,
+ const SourceLocation Point) {
+ const SourceManager &SM = Context.getSourceManager();
+ NamedDeclOccurrenceFindingVisitor Visitor(Point, Context);
+
+ // Try to be clever about pruning down the number of top-level declarations we
+ // see. If both start and end is either before or after the point we're
+ // looking for the point cannot be inside of this decl. Don't even look at it.
+ for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
+ SourceLocation StartLoc = CurrDecl->getBeginLoc();
+ SourceLocation EndLoc = CurrDecl->getEndLoc();
+ if (StartLoc.isValid() && EndLoc.isValid() &&
+ SM.isBeforeInTranslationUnit(StartLoc, Point) !=
+ SM.isBeforeInTranslationUnit(EndLoc, Point))
+ Visitor.TraverseDecl(CurrDecl);
+ }
+
+ return Visitor.getNamedDecl();
+}
+
+namespace {
+
+/// Recursively visits each NamedDecl node to find the declaration with a
+/// specific name.
+class NamedDeclFindingVisitor
+ : public RecursiveASTVisitor<NamedDeclFindingVisitor> {
+public:
+ explicit NamedDeclFindingVisitor(StringRef Name) : Name(Name) {}
+
+ // We don't have to traverse the uses to find some declaration with a
+ // specific name, so just visit the named declarations.
+ bool VisitNamedDecl(const NamedDecl *ND) {
+ if (!ND)
+ return true;
+ // Fully qualified name is used to find the declaration.
+ if (Name != ND->getQualifiedNameAsString() &&
+ Name != "::" + ND->getQualifiedNameAsString())
+ return true;
+ Result = ND;
+ return false;
+ }
+
+ const NamedDecl *getNamedDecl() const { return Result; }
+
+private:
+ const NamedDecl *Result = nullptr;
+ StringRef Name;
+};
+
+} // end anonymous namespace
+
+const NamedDecl *getNamedDeclFor(const ASTContext &Context,
+ const std::string &Name) {
+ NamedDeclFindingVisitor Visitor(Name);
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ return Visitor.getNamedDecl();
+}
+
+std::string getUSRForDecl(const Decl *Decl) {
+ llvm::SmallVector<char, 128> Buff;
+
+ // FIXME: Add test for the nullptr case.
+ if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
+ return "";
+
+ return std::string(Buff.data(), Buff.size());
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
new file mode 100644
index 000000000000..2e7c9b0cc31b
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
@@ -0,0 +1,274 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Provides an action to find USR for the symbol at <offset>, as well as
+/// all additional USRs.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "clang/Tooling/Tooling.h"
+
+#include <algorithm>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+const NamedDecl *getCanonicalSymbolDeclaration(const NamedDecl *FoundDecl) {
+ // If FoundDecl is a constructor or destructor, we want to instead take
+ // the Decl of the corresponding class.
+ if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
+ FoundDecl = CtorDecl->getParent();
+ else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl))
+ FoundDecl = DtorDecl->getParent();
+ // FIXME: (Alex L): Canonicalize implicit template instantions, just like
+ // the indexer does it.
+
+ // Note: please update the declaration's doc comment every time the
+ // canonicalization rules are changed.
+ return FoundDecl;
+}
+
+namespace {
+// NamedDeclFindingConsumer should delegate finding USRs of given Decl to
+// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given
+// Decl refers to class and adds USRs of all overridden methods if Decl refers
+// to virtual method.
+class AdditionalUSRFinder : public RecursiveASTVisitor<AdditionalUSRFinder> {
+public:
+ AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context)
+ : FoundDecl(FoundDecl), Context(Context) {}
+
+ std::vector<std::string> Find() {
+ // Fill OverriddenMethods and PartialSpecs storages.
+ TraverseDecl(Context.getTranslationUnitDecl());
+ if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
+ addUSRsOfOverridenFunctions(MethodDecl);
+ for (const auto &OverriddenMethod : OverriddenMethods) {
+ if (checkIfOverriddenFunctionAscends(OverriddenMethod))
+ USRSet.insert(getUSRForDecl(OverriddenMethod));
+ }
+ addUSRsOfInstantiatedMethods(MethodDecl);
+ } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl)) {
+ handleCXXRecordDecl(RecordDecl);
+ } else if (const auto *TemplateDecl =
+ dyn_cast<ClassTemplateDecl>(FoundDecl)) {
+ handleClassTemplateDecl(TemplateDecl);
+ } else {
+ USRSet.insert(getUSRForDecl(FoundDecl));
+ }
+ return std::vector<std::string>(USRSet.begin(), USRSet.end());
+ }
+
+ bool shouldVisitTemplateInstantiations() const { return true; }
+
+ bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) {
+ if (MethodDecl->isVirtual())
+ OverriddenMethods.push_back(MethodDecl);
+ if (MethodDecl->getInstantiatedFromMemberFunction())
+ InstantiatedMethods.push_back(MethodDecl);
+ return true;
+ }
+
+ bool VisitClassTemplatePartialSpecializationDecl(
+ const ClassTemplatePartialSpecializationDecl *PartialSpec) {
+ PartialSpecs.push_back(PartialSpec);
+ return true;
+ }
+
+private:
+ void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) {
+ RecordDecl = RecordDecl->getDefinition();
+ if (const auto *ClassTemplateSpecDecl =
+ dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl))
+ handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate());
+ addUSRsOfCtorDtors(RecordDecl);
+ }
+
+ void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) {
+ for (const auto *Specialization : TemplateDecl->specializations())
+ addUSRsOfCtorDtors(Specialization);
+
+ for (const auto *PartialSpec : PartialSpecs) {
+ if (PartialSpec->getSpecializedTemplate() == TemplateDecl)
+ addUSRsOfCtorDtors(PartialSpec);
+ }
+ addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl());
+ }
+
+ void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) {
+ RecordDecl = RecordDecl->getDefinition();
+
+ // Skip if the CXXRecordDecl doesn't have definition.
+ if (!RecordDecl)
+ return;
+
+ for (const auto *CtorDecl : RecordDecl->ctors())
+ USRSet.insert(getUSRForDecl(CtorDecl));
+
+ USRSet.insert(getUSRForDecl(RecordDecl->getDestructor()));
+ USRSet.insert(getUSRForDecl(RecordDecl));
+ }
+
+ void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) {
+ USRSet.insert(getUSRForDecl(MethodDecl));
+ // Recursively visit each OverridenMethod.
+ for (const auto &OverriddenMethod : MethodDecl->overridden_methods())
+ addUSRsOfOverridenFunctions(OverriddenMethod);
+ }
+
+ void addUSRsOfInstantiatedMethods(const CXXMethodDecl *MethodDecl) {
+ // For renaming a class template method, all references of the instantiated
+ // member methods should be renamed too, so add USRs of the instantiated
+ // methods to the USR set.
+ USRSet.insert(getUSRForDecl(MethodDecl));
+ if (const auto *FT = MethodDecl->getInstantiatedFromMemberFunction())
+ USRSet.insert(getUSRForDecl(FT));
+ for (const auto *Method : InstantiatedMethods) {
+ if (USRSet.find(getUSRForDecl(
+ Method->getInstantiatedFromMemberFunction())) != USRSet.end())
+ USRSet.insert(getUSRForDecl(Method));
+ }
+ }
+
+ bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) {
+ for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) {
+ if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end())
+ return true;
+ return checkIfOverriddenFunctionAscends(OverriddenMethod);
+ }
+ return false;
+ }
+
+ const Decl *FoundDecl;
+ ASTContext &Context;
+ std::set<std::string> USRSet;
+ std::vector<const CXXMethodDecl *> OverriddenMethods;
+ std::vector<const CXXMethodDecl *> InstantiatedMethods;
+ std::vector<const ClassTemplatePartialSpecializationDecl *> PartialSpecs;
+};
+} // namespace
+
+std::vector<std::string> getUSRsForDeclaration(const NamedDecl *ND,
+ ASTContext &Context) {
+ AdditionalUSRFinder Finder(ND, Context);
+ return Finder.Find();
+}
+
+class NamedDeclFindingConsumer : public ASTConsumer {
+public:
+ NamedDeclFindingConsumer(ArrayRef<unsigned> SymbolOffsets,
+ ArrayRef<std::string> QualifiedNames,
+ std::vector<std::string> &SpellingNames,
+ std::vector<std::vector<std::string>> &USRList,
+ bool Force, bool &ErrorOccurred)
+ : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
+ SpellingNames(SpellingNames), USRList(USRList), Force(Force),
+ ErrorOccurred(ErrorOccurred) {}
+
+private:
+ bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr,
+ unsigned SymbolOffset, const std::string &QualifiedName) {
+ DiagnosticsEngine &Engine = Context.getDiagnostics();
+ const FileID MainFileID = SourceMgr.getMainFileID();
+
+ if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) {
+ ErrorOccurred = true;
+ unsigned InvalidOffset = Engine.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "SourceLocation in file %0 at offset %1 is invalid");
+ Engine.Report(SourceLocation(), InvalidOffset)
+ << SourceMgr.getFileEntryForID(MainFileID)->getName() << SymbolOffset;
+ return false;
+ }
+
+ const SourceLocation Point = SourceMgr.getLocForStartOfFile(MainFileID)
+ .getLocWithOffset(SymbolOffset);
+ const NamedDecl *FoundDecl = QualifiedName.empty()
+ ? getNamedDeclAt(Context, Point)
+ : getNamedDeclFor(Context, QualifiedName);
+
+ if (FoundDecl == nullptr) {
+ if (QualifiedName.empty()) {
+ FullSourceLoc FullLoc(Point, SourceMgr);
+ unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "clang-rename could not find symbol (offset %0)");
+ Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset;
+ ErrorOccurred = true;
+ return false;
+ }
+
+ if (Force) {
+ SpellingNames.push_back(std::string());
+ USRList.push_back(std::vector<std::string>());
+ return true;
+ }
+
+ unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID(
+ DiagnosticsEngine::Error, "clang-rename could not find symbol %0");
+ Engine.Report(CouldNotFindSymbolNamed) << QualifiedName;
+ ErrorOccurred = true;
+ return false;
+ }
+
+ FoundDecl = getCanonicalSymbolDeclaration(FoundDecl);
+ SpellingNames.push_back(FoundDecl->getNameAsString());
+ AdditionalUSRFinder Finder(FoundDecl, Context);
+ USRList.push_back(Finder.Find());
+ return true;
+ }
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ const SourceManager &SourceMgr = Context.getSourceManager();
+ for (unsigned Offset : SymbolOffsets) {
+ if (!FindSymbol(Context, SourceMgr, Offset, ""))
+ return;
+ }
+ for (const std::string &QualifiedName : QualifiedNames) {
+ if (!FindSymbol(Context, SourceMgr, 0, QualifiedName))
+ return;
+ }
+ }
+
+ ArrayRef<unsigned> SymbolOffsets;
+ ArrayRef<std::string> QualifiedNames;
+ std::vector<std::string> &SpellingNames;
+ std::vector<std::vector<std::string>> &USRList;
+ bool Force;
+ bool &ErrorOccurred;
+};
+
+std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
+ return llvm::make_unique<NamedDeclFindingConsumer>(
+ SymbolOffsets, QualifiedNames, SpellingNames, USRList, Force,
+ ErrorOccurred);
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
new file mode 100644
index 000000000000..7f60cf54c8ec
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
@@ -0,0 +1,585 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Methods for finding all instances of a USR. Our strategy is very
+/// simple; we just compare the USR at every relevant AST node with the one
+/// provided.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Core/Lookup.h"
+#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include <cstddef>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+// Returns true if the given Loc is valid for edit. We don't edit the
+// SourceLocations that are valid or in temporary buffer.
+bool IsValidEditLoc(const clang::SourceManager& SM, clang::SourceLocation Loc) {
+ if (Loc.isInvalid())
+ return false;
+ const clang::FullSourceLoc FullLoc(Loc, SM);
+ std::pair<clang::FileID, unsigned> FileIdAndOffset =
+ FullLoc.getSpellingLoc().getDecomposedLoc();
+ return SM.getFileEntryForID(FileIdAndOffset.first) != nullptr;
+}
+
+// This visitor recursively searches for all instances of a USR in a
+// translation unit and stores them for later usage.
+class USRLocFindingASTVisitor
+ : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> {
+public:
+ explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs,
+ StringRef PrevName,
+ const ASTContext &Context)
+ : RecursiveSymbolVisitor(Context.getSourceManager(),
+ Context.getLangOpts()),
+ USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {
+ }
+
+ bool visitSymbolOccurrence(const NamedDecl *ND,
+ ArrayRef<SourceRange> NameRanges) {
+ if (USRSet.find(getUSRForDecl(ND)) != USRSet.end()) {
+ assert(NameRanges.size() == 1 &&
+ "Multiple name pieces are not supported yet!");
+ SourceLocation Loc = NameRanges[0].getBegin();
+ const SourceManager &SM = Context.getSourceManager();
+ // TODO: Deal with macro occurrences correctly.
+ if (Loc.isMacroID())
+ Loc = SM.getSpellingLoc(Loc);
+ checkAndAddLocation(Loc);
+ }
+ return true;
+ }
+
+ // Non-visitors:
+
+ /// Returns a set of unique symbol occurrences. Duplicate or
+ /// overlapping occurrences are erroneous and should be reported!
+ SymbolOccurrences takeOccurrences() { return std::move(Occurrences); }
+
+private:
+ void checkAndAddLocation(SourceLocation Loc) {
+ const SourceLocation BeginLoc = Loc;
+ const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
+ StringRef TokenName =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
+ Context.getSourceManager(), Context.getLangOpts());
+ size_t Offset = TokenName.find(PrevName.getNamePieces()[0]);
+
+ // The token of the source location we find actually has the old
+ // name.
+ if (Offset != StringRef::npos)
+ Occurrences.emplace_back(PrevName, SymbolOccurrence::MatchingSymbol,
+ BeginLoc.getLocWithOffset(Offset));
+ }
+
+ const std::set<std::string> USRSet;
+ const SymbolName PrevName;
+ SymbolOccurrences Occurrences;
+ const ASTContext &Context;
+};
+
+SourceLocation StartLocationForType(TypeLoc TL) {
+ // For elaborated types (e.g. `struct a::A`) we want the portion after the
+ // `struct` but including the namespace qualifier, `a::`.
+ if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) {
+ NestedNameSpecifierLoc NestedNameSpecifier =
+ ElaboratedTypeLoc.getQualifierLoc();
+ if (NestedNameSpecifier.getNestedNameSpecifier())
+ return NestedNameSpecifier.getBeginLoc();
+ TL = TL.getNextTypeLoc();
+ }
+ return TL.getBeginLoc();
+}
+
+SourceLocation EndLocationForType(TypeLoc TL) {
+ // Dig past any namespace or keyword qualifications.
+ while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
+ TL.getTypeLocClass() == TypeLoc::Qualified)
+ TL = TL.getNextTypeLoc();
+
+ // The location for template specializations (e.g. Foo<int>) includes the
+ // templated types in its location range. We want to restrict this to just
+ // before the `<` character.
+ if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
+ return TL.castAs<TemplateSpecializationTypeLoc>()
+ .getLAngleLoc()
+ .getLocWithOffset(-1);
+ }
+ return TL.getEndLoc();
+}
+
+NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
+ // Dig past any keyword qualifications.
+ while (TL.getTypeLocClass() == TypeLoc::Qualified)
+ TL = TL.getNextTypeLoc();
+
+ // For elaborated types (e.g. `struct a::A`) we want the portion after the
+ // `struct` but including the namespace qualifier, `a::`.
+ if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>())
+ return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
+ return nullptr;
+}
+
+// Find all locations identified by the given USRs for rename.
+//
+// This class will traverse the AST and find every AST node whose USR is in the
+// given USRs' set.
+class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> {
+public:
+ RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context)
+ : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
+
+ // A structure records all information of a symbol reference being renamed.
+ // We try to add as few prefix qualifiers as possible.
+ struct RenameInfo {
+ // The begin location of a symbol being renamed.
+ SourceLocation Begin;
+ // The end location of a symbol being renamed.
+ SourceLocation End;
+ // The declaration of a symbol being renamed (can be nullptr).
+ const NamedDecl *FromDecl;
+ // The declaration in which the nested name is contained (can be nullptr).
+ const Decl *Context;
+ // The nested name being replaced (can be nullptr).
+ const NestedNameSpecifier *Specifier;
+ // Determine whether the prefix qualifiers of the NewName should be ignored.
+ // Normally, we set it to true for the symbol declaration and definition to
+ // avoid adding prefix qualifiers.
+ // For example, if it is true and NewName is "a::b::foo", then the symbol
+ // occurrence which the RenameInfo points to will be renamed to "foo".
+ bool IgnorePrefixQualifers;
+ };
+
+ bool VisitNamedDecl(const NamedDecl *Decl) {
+ // UsingDecl has been handled in other place.
+ if (llvm::isa<UsingDecl>(Decl))
+ return true;
+
+ // DestructorDecl has been handled in Typeloc.
+ if (llvm::isa<CXXDestructorDecl>(Decl))
+ return true;
+
+ if (Decl->isImplicit())
+ return true;
+
+ if (isInUSRSet(Decl)) {
+ // For the case of renaming an alias template, we actually rename the
+ // underlying alias declaration of the template.
+ if (const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Decl))
+ Decl = TAT->getTemplatedDecl();
+
+ auto StartLoc = Decl->getLocation();
+ auto EndLoc = StartLoc;
+ if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
+ RenameInfo Info = {StartLoc,
+ EndLoc,
+ /*FromDecl=*/nullptr,
+ /*Context=*/nullptr,
+ /*Specifier=*/nullptr,
+ /*IgnorePrefixQualifers=*/true};
+ RenameInfos.push_back(Info);
+ }
+ }
+ return true;
+ }
+
+ bool VisitMemberExpr(const MemberExpr *Expr) {
+ const NamedDecl *Decl = Expr->getFoundDecl();
+ auto StartLoc = Expr->getMemberLoc();
+ auto EndLoc = Expr->getMemberLoc();
+ if (isInUSRSet(Decl)) {
+ RenameInfos.push_back({StartLoc, EndLoc,
+ /*FromDecl=*/nullptr,
+ /*Context=*/nullptr,
+ /*Specifier=*/nullptr,
+ /*IgnorePrefixQualifiers=*/true});
+ }
+ return true;
+ }
+
+ bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
+ // Fix the constructor initializer when renaming class members.
+ for (const auto *Initializer : CD->inits()) {
+ // Ignore implicit initializers.
+ if (!Initializer->isWritten())
+ continue;
+
+ if (const FieldDecl *FD = Initializer->getMember()) {
+ if (isInUSRSet(FD)) {
+ auto Loc = Initializer->getSourceLocation();
+ RenameInfos.push_back({Loc, Loc,
+ /*FromDecl=*/nullptr,
+ /*Context=*/nullptr,
+ /*Specifier=*/nullptr,
+ /*IgnorePrefixQualifiers=*/true});
+ }
+ }
+ }
+ return true;
+ }
+
+ bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
+ const NamedDecl *Decl = Expr->getFoundDecl();
+ // Get the underlying declaration of the shadow declaration introduced by a
+ // using declaration.
+ if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) {
+ Decl = UsingShadow->getTargetDecl();
+ }
+
+ auto StartLoc = Expr->getBeginLoc();
+ // For template function call expressions like `foo<int>()`, we want to
+ // restrict the end of location to just before the `<` character.
+ SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()
+ ? Expr->getLAngleLoc().getLocWithOffset(-1)
+ : Expr->getEndLoc();
+
+ if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) {
+ if (isInUSRSet(MD)) {
+ // Handle renaming static template class methods, we only rename the
+ // name without prefix qualifiers and restrict the source range to the
+ // name.
+ RenameInfos.push_back({EndLoc, EndLoc,
+ /*FromDecl=*/nullptr,
+ /*Context=*/nullptr,
+ /*Specifier=*/nullptr,
+ /*IgnorePrefixQualifiers=*/true});
+ return true;
+ }
+ }
+
+ // In case of renaming an enum declaration, we have to explicitly handle
+ // unscoped enum constants referenced in expressions (e.g.
+ // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped
+ // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by
+ // TypeLoc.
+ if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) {
+ // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`)
+ // when renaming an unscoped enum declaration with a new namespace.
+ if (!Expr->hasQualifier())
+ return true;
+
+ if (const auto *ED =
+ llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) {
+ if (ED->isScoped())
+ return true;
+ Decl = ED;
+ }
+ // The current fix would qualify "ns1::ns2::Green" as
+ // "ns1::ns2::Color::Green".
+ //
+ // Get the EndLoc of the replacement by moving 1 character backward (
+ // to exclude the last '::').
+ //
+ // ns1::ns2::Green;
+ // ^ ^^
+ // BeginLoc |EndLoc of the qualifier
+ // new EndLoc
+ EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1);
+ assert(EndLoc.isValid() &&
+ "The enum constant should have prefix qualifers.");
+ }
+ if (isInUSRSet(Decl) &&
+ IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
+ RenameInfo Info = {StartLoc,
+ EndLoc,
+ Decl,
+ getClosestAncestorDecl(*Expr),
+ Expr->getQualifier(),
+ /*IgnorePrefixQualifers=*/false};
+ RenameInfos.push_back(Info);
+ }
+
+ return true;
+ }
+
+ bool VisitUsingDecl(const UsingDecl *Using) {
+ for (const auto *UsingShadow : Using->shadows()) {
+ if (isInUSRSet(UsingShadow->getTargetDecl())) {
+ UsingDecls.push_back(Using);
+ break;
+ }
+ }
+ return true;
+ }
+
+ bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
+ if (!NestedLoc.getNestedNameSpecifier()->getAsType())
+ return true;
+
+ if (const auto *TargetDecl =
+ getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
+ if (isInUSRSet(TargetDecl)) {
+ RenameInfo Info = {NestedLoc.getBeginLoc(),
+ EndLocationForType(NestedLoc.getTypeLoc()),
+ TargetDecl,
+ getClosestAncestorDecl(NestedLoc),
+ NestedLoc.getNestedNameSpecifier()->getPrefix(),
+ /*IgnorePrefixQualifers=*/false};
+ RenameInfos.push_back(Info);
+ }
+ }
+ return true;
+ }
+
+ bool VisitTypeLoc(TypeLoc Loc) {
+ auto Parents = Context.getParents(Loc);
+ TypeLoc ParentTypeLoc;
+ if (!Parents.empty()) {
+ // Handle cases of nested name specificier locations.
+ //
+ // The VisitNestedNameSpecifierLoc interface is not impelmented in
+ // RecursiveASTVisitor, we have to handle it explicitly.
+ if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
+ VisitNestedNameSpecifierLocations(*NSL);
+ return true;
+ }
+
+ if (const auto *TL = Parents[0].get<TypeLoc>())
+ ParentTypeLoc = *TL;
+ }
+
+ // Handle the outermost TypeLoc which is directly linked to the interesting
+ // declaration and don't handle nested name specifier locations.
+ if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
+ if (isInUSRSet(TargetDecl)) {
+ // Only handle the outermost typeLoc.
+ //
+ // For a type like "a::Foo", there will be two typeLocs for it.
+ // One ElaboratedType, the other is RecordType:
+ //
+ // ElaboratedType 0x33b9390 'a::Foo' sugar
+ // `-RecordType 0x338fef0 'class a::Foo'
+ // `-CXXRecord 0x338fe58 'Foo'
+ //
+ // Skip if this is an inner typeLoc.
+ if (!ParentTypeLoc.isNull() &&
+ isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
+ return true;
+
+ auto StartLoc = StartLocationForType(Loc);
+ auto EndLoc = EndLocationForType(Loc);
+ if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
+ RenameInfo Info = {StartLoc,
+ EndLoc,
+ TargetDecl,
+ getClosestAncestorDecl(Loc),
+ GetNestedNameForType(Loc),
+ /*IgnorePrefixQualifers=*/false};
+ RenameInfos.push_back(Info);
+ }
+ return true;
+ }
+ }
+
+ // Handle specific template class specialiation cases.
+ if (const auto *TemplateSpecType =
+ dyn_cast<TemplateSpecializationType>(Loc.getType())) {
+ TypeLoc TargetLoc = Loc;
+ if (!ParentTypeLoc.isNull()) {
+ if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
+ TargetLoc = ParentTypeLoc;
+ }
+
+ if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
+ TypeLoc TargetLoc = Loc;
+ // FIXME: Find a better way to handle this case.
+ // For the qualified template class specification type like
+ // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc
+ // (ElaboratedType) of the TemplateSpecializationType in order to
+ // catch the prefix qualifiers "ns::".
+ if (!ParentTypeLoc.isNull() &&
+ llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
+ TargetLoc = ParentTypeLoc;
+
+ auto StartLoc = StartLocationForType(TargetLoc);
+ auto EndLoc = EndLocationForType(TargetLoc);
+ if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
+ RenameInfo Info = {
+ StartLoc,
+ EndLoc,
+ TemplateSpecType->getTemplateName().getAsTemplateDecl(),
+ getClosestAncestorDecl(
+ ast_type_traits::DynTypedNode::create(TargetLoc)),
+ GetNestedNameForType(TargetLoc),
+ /*IgnorePrefixQualifers=*/false};
+ RenameInfos.push_back(Info);
+ }
+ }
+ }
+ return true;
+ }
+
+ // Returns a list of RenameInfo.
+ const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; }
+
+ // Returns a list of using declarations which are needed to update.
+ const std::vector<const UsingDecl *> &getUsingDecls() const {
+ return UsingDecls;
+ }
+
+private:
+ // Get the supported declaration from a given typeLoc. If the declaration type
+ // is not supported, returns nullptr.
+ const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
+ if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>())
+ return TT->getDecl();
+ if (const auto *RD = Loc.getType()->getAsCXXRecordDecl())
+ return RD;
+ if (const auto *ED =
+ llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl()))
+ return ED;
+ return nullptr;
+ }
+
+ // Get the closest ancester which is a declaration of a given AST node.
+ template <typename ASTNodeType>
+ const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {
+ auto Parents = Context.getParents(Node);
+ // FIXME: figure out how to handle it when there are multiple parents.
+ if (Parents.size() != 1)
+ return nullptr;
+ if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(
+ Parents[0].getNodeKind()))
+ return Parents[0].template get<Decl>();
+ return getClosestAncestorDecl(Parents[0]);
+ }
+
+ // Get the parent typeLoc of a given typeLoc. If there is no such parent,
+ // return nullptr.
+ const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {
+ auto Parents = Context.getParents(Loc);
+ // FIXME: figure out how to handle it when there are multiple parents.
+ if (Parents.size() != 1)
+ return nullptr;
+ return Parents[0].get<TypeLoc>();
+ }
+
+ // Check whether the USR of a given Decl is in the USRSet.
+ bool isInUSRSet(const Decl *Decl) const {
+ auto USR = getUSRForDecl(Decl);
+ if (USR.empty())
+ return false;
+ return llvm::is_contained(USRSet, USR);
+ }
+
+ const std::set<std::string> USRSet;
+ ASTContext &Context;
+ std::vector<RenameInfo> RenameInfos;
+ // Record all interested using declarations which contains the using-shadow
+ // declarations of the symbol declarations being renamed.
+ std::vector<const UsingDecl *> UsingDecls;
+};
+
+} // namespace
+
+SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs,
+ StringRef PrevName, Decl *Decl) {
+ USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());
+ Visitor.TraverseDecl(Decl);
+ return Visitor.takeOccurrences();
+}
+
+std::vector<tooling::AtomicChange>
+createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
+ llvm::StringRef NewName, Decl *TranslationUnitDecl) {
+ RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext());
+ Finder.TraverseDecl(TranslationUnitDecl);
+
+ const SourceManager &SM =
+ TranslationUnitDecl->getASTContext().getSourceManager();
+
+ std::vector<tooling::AtomicChange> AtomicChanges;
+ auto Replace = [&](SourceLocation Start, SourceLocation End,
+ llvm::StringRef Text) {
+ tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start);
+ llvm::Error Err = ReplaceChange.replace(
+ SM, CharSourceRange::getTokenRange(Start, End), Text);
+ if (Err) {
+ llvm::errs() << "Failed to add replacement to AtomicChange: "
+ << llvm::toString(std::move(Err)) << "\n";
+ return;
+ }
+ AtomicChanges.push_back(std::move(ReplaceChange));
+ };
+
+ for (const auto &RenameInfo : Finder.getRenameInfos()) {
+ std::string ReplacedName = NewName.str();
+ if (RenameInfo.IgnorePrefixQualifers) {
+ // Get the name without prefix qualifiers from NewName.
+ size_t LastColonPos = NewName.find_last_of(':');
+ if (LastColonPos != std::string::npos)
+ ReplacedName = NewName.substr(LastColonPos + 1);
+ } else {
+ if (RenameInfo.FromDecl && RenameInfo.Context) {
+ if (!llvm::isa<clang::TranslationUnitDecl>(
+ RenameInfo.Context->getDeclContext())) {
+ ReplacedName = tooling::replaceNestedName(
+ RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
+ RenameInfo.FromDecl,
+ NewName.startswith("::") ? NewName.str()
+ : ("::" + NewName).str());
+ } else {
+ // This fixes the case where type `T` is a parameter inside a function
+ // type (e.g. `std::function<void(T)>`) and the DeclContext of `T`
+ // becomes the translation unit. As a workaround, we simply use
+ // fully-qualified name here for all references whose `DeclContext` is
+ // the translation unit and ignore the possible existence of
+ // using-decls (in the global scope) that can shorten the replaced
+ // name.
+ llvm::StringRef ActualName = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(
+ SourceRange(RenameInfo.Begin, RenameInfo.End)),
+ SM, TranslationUnitDecl->getASTContext().getLangOpts());
+ // Add the leading "::" back if the name written in the code contains
+ // it.
+ if (ActualName.startswith("::") && !NewName.startswith("::")) {
+ ReplacedName = "::" + NewName.str();
+ }
+ }
+ }
+ // If the NewName contains leading "::", add it back.
+ if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)
+ ReplacedName = NewName.str();
+ }
+ Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
+ }
+
+ // Hanlde using declarations explicitly as "using a::Foo" don't trigger
+ // typeLoc for "a::Foo".
+ for (const auto *Using : Finder.getUsingDecls())
+ Replace(Using->getBeginLoc(), Using->getEndLoc(), "using " + NewName.str());
+
+ return AtomicChanges;
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/RefactoringCallbacks.cpp b/contrib/llvm/tools/clang/lib/Tooling/RefactoringCallbacks.cpp
new file mode 100644
index 000000000000..9fd333ca554e
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/RefactoringCallbacks.cpp
@@ -0,0 +1,241 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Tooling/RefactoringCallbacks.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+
+using llvm::StringError;
+using llvm::make_error;
+
+namespace clang {
+namespace tooling {
+
+RefactoringCallback::RefactoringCallback() {}
+tooling::Replacements &RefactoringCallback::getReplacements() {
+ return Replace;
+}
+
+ASTMatchRefactorer::ASTMatchRefactorer(
+ std::map<std::string, Replacements> &FileToReplaces)
+ : FileToReplaces(FileToReplaces) {}
+
+void ASTMatchRefactorer::addDynamicMatcher(
+ const ast_matchers::internal::DynTypedMatcher &Matcher,
+ RefactoringCallback *Callback) {
+ MatchFinder.addDynamicMatcher(Matcher, Callback);
+ Callbacks.push_back(Callback);
+}
+
+class RefactoringASTConsumer : public ASTConsumer {
+public:
+ explicit RefactoringASTConsumer(ASTMatchRefactorer &Refactoring)
+ : Refactoring(Refactoring) {}
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ // The ASTMatchRefactorer is re-used between translation units.
+ // Clear the matchers so that each Replacement is only emitted once.
+ for (const auto &Callback : Refactoring.Callbacks) {
+ Callback->getReplacements().clear();
+ }
+ Refactoring.MatchFinder.matchAST(Context);
+ for (const auto &Callback : Refactoring.Callbacks) {
+ for (const auto &Replacement : Callback->getReplacements()) {
+ llvm::Error Err =
+ Refactoring.FileToReplaces[Replacement.getFilePath()].add(
+ Replacement);
+ if (Err) {
+ llvm::errs() << "Skipping replacement " << Replacement.toString()
+ << " due to this error:\n"
+ << toString(std::move(Err)) << "\n";
+ }
+ }
+ }
+ }
+
+private:
+ ASTMatchRefactorer &Refactoring;
+};
+
+std::unique_ptr<ASTConsumer> ASTMatchRefactorer::newASTConsumer() {
+ return llvm::make_unique<RefactoringASTConsumer>(*this);
+}
+
+static Replacement replaceStmtWithText(SourceManager &Sources, const Stmt &From,
+ StringRef Text) {
+ return tooling::Replacement(
+ Sources, CharSourceRange::getTokenRange(From.getSourceRange()), Text);
+}
+static Replacement replaceStmtWithStmt(SourceManager &Sources, const Stmt &From,
+ const Stmt &To) {
+ return replaceStmtWithText(
+ Sources, From,
+ Lexer::getSourceText(CharSourceRange::getTokenRange(To.getSourceRange()),
+ Sources, LangOptions()));
+}
+
+ReplaceStmtWithText::ReplaceStmtWithText(StringRef FromId, StringRef ToText)
+ : FromId(FromId), ToText(ToText) {}
+
+void ReplaceStmtWithText::run(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ if (const Stmt *FromMatch = Result.Nodes.getNodeAs<Stmt>(FromId)) {
+ auto Err = Replace.add(tooling::Replacement(
+ *Result.SourceManager,
+ CharSourceRange::getTokenRange(FromMatch->getSourceRange()), ToText));
+ // FIXME: better error handling. For now, just print error message in the
+ // release version.
+ if (Err) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(false);
+ }
+ }
+}
+
+ReplaceStmtWithStmt::ReplaceStmtWithStmt(StringRef FromId, StringRef ToId)
+ : FromId(FromId), ToId(ToId) {}
+
+void ReplaceStmtWithStmt::run(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ const Stmt *FromMatch = Result.Nodes.getNodeAs<Stmt>(FromId);
+ const Stmt *ToMatch = Result.Nodes.getNodeAs<Stmt>(ToId);
+ if (FromMatch && ToMatch) {
+ auto Err = Replace.add(
+ replaceStmtWithStmt(*Result.SourceManager, *FromMatch, *ToMatch));
+ // FIXME: better error handling. For now, just print error message in the
+ // release version.
+ if (Err) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(false);
+ }
+ }
+}
+
+ReplaceIfStmtWithItsBody::ReplaceIfStmtWithItsBody(StringRef Id,
+ bool PickTrueBranch)
+ : Id(Id), PickTrueBranch(PickTrueBranch) {}
+
+void ReplaceIfStmtWithItsBody::run(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ if (const IfStmt *Node = Result.Nodes.getNodeAs<IfStmt>(Id)) {
+ const Stmt *Body = PickTrueBranch ? Node->getThen() : Node->getElse();
+ if (Body) {
+ auto Err =
+ Replace.add(replaceStmtWithStmt(*Result.SourceManager, *Node, *Body));
+ // FIXME: better error handling. For now, just print error message in the
+ // release version.
+ if (Err) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(false);
+ }
+ } else if (!PickTrueBranch) {
+ // If we want to use the 'else'-branch, but it doesn't exist, delete
+ // the whole 'if'.
+ auto Err =
+ Replace.add(replaceStmtWithText(*Result.SourceManager, *Node, ""));
+ // FIXME: better error handling. For now, just print error message in the
+ // release version.
+ if (Err) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(false);
+ }
+ }
+ }
+}
+
+ReplaceNodeWithTemplate::ReplaceNodeWithTemplate(
+ llvm::StringRef FromId, std::vector<TemplateElement> Template)
+ : FromId(FromId), Template(std::move(Template)) {}
+
+llvm::Expected<std::unique_ptr<ReplaceNodeWithTemplate>>
+ReplaceNodeWithTemplate::create(StringRef FromId, StringRef ToTemplate) {
+ std::vector<TemplateElement> ParsedTemplate;
+ for (size_t Index = 0; Index < ToTemplate.size();) {
+ if (ToTemplate[Index] == '$') {
+ if (ToTemplate.substr(Index, 2) == "$$") {
+ Index += 2;
+ ParsedTemplate.push_back(
+ TemplateElement{TemplateElement::Literal, "$"});
+ } else if (ToTemplate.substr(Index, 2) == "${") {
+ size_t EndOfIdentifier = ToTemplate.find("}", Index);
+ if (EndOfIdentifier == std::string::npos) {
+ return make_error<StringError>(
+ "Unterminated ${...} in replacement template near " +
+ ToTemplate.substr(Index),
+ llvm::inconvertibleErrorCode());
+ }
+ std::string SourceNodeName =
+ ToTemplate.substr(Index + 2, EndOfIdentifier - Index - 2);
+ ParsedTemplate.push_back(
+ TemplateElement{TemplateElement::Identifier, SourceNodeName});
+ Index = EndOfIdentifier + 1;
+ } else {
+ return make_error<StringError>(
+ "Invalid $ in replacement template near " +
+ ToTemplate.substr(Index),
+ llvm::inconvertibleErrorCode());
+ }
+ } else {
+ size_t NextIndex = ToTemplate.find('$', Index + 1);
+ ParsedTemplate.push_back(
+ TemplateElement{TemplateElement::Literal,
+ ToTemplate.substr(Index, NextIndex - Index)});
+ Index = NextIndex;
+ }
+ }
+ return std::unique_ptr<ReplaceNodeWithTemplate>(
+ new ReplaceNodeWithTemplate(FromId, std::move(ParsedTemplate)));
+}
+
+void ReplaceNodeWithTemplate::run(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ const auto &NodeMap = Result.Nodes.getMap();
+
+ std::string ToText;
+ for (const auto &Element : Template) {
+ switch (Element.Type) {
+ case TemplateElement::Literal:
+ ToText += Element.Value;
+ break;
+ case TemplateElement::Identifier: {
+ auto NodeIter = NodeMap.find(Element.Value);
+ if (NodeIter == NodeMap.end()) {
+ llvm::errs() << "Node " << Element.Value
+ << " used in replacement template not bound in Matcher \n";
+ llvm::report_fatal_error("Unbound node in replacement template.");
+ }
+ CharSourceRange Source =
+ CharSourceRange::getTokenRange(NodeIter->second.getSourceRange());
+ ToText += Lexer::getSourceText(Source, *Result.SourceManager,
+ Result.Context->getLangOpts());
+ break;
+ }
+ }
+ }
+ if (NodeMap.count(FromId) == 0) {
+ llvm::errs() << "Node to be replaced " << FromId
+ << " not bound in query.\n";
+ llvm::report_fatal_error("FromId node not bound in MatchResult");
+ }
+ auto Replacement =
+ tooling::Replacement(*Result.SourceManager, &NodeMap.at(FromId), ToText,
+ Result.Context->getLangOpts());
+ llvm::Error Err = Replace.add(Replacement);
+ if (Err) {
+ llvm::errs() << "Query and replace failed in " << Replacement.getFilePath()
+ << "! " << llvm::toString(std::move(Err)) << "\n";
+ llvm::report_fatal_error("Replacement failed");
+ }
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/StandaloneExecution.cpp b/contrib/llvm/tools/clang/lib/Tooling/StandaloneExecution.cpp
new file mode 100644
index 000000000000..1daf792fb86f
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/StandaloneExecution.cpp
@@ -0,0 +1,93 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/StandaloneExecution.h"
+#include "clang/Tooling/ToolExecutorPluginRegistry.h"
+
+namespace clang {
+namespace tooling {
+
+static llvm::Error make_string_error(const llvm::Twine &Message) {
+ return llvm::make_error<llvm::StringError>(Message,
+ llvm::inconvertibleErrorCode());
+}
+
+const char *StandaloneToolExecutor::ExecutorName = "StandaloneToolExecutor";
+
+static ArgumentsAdjuster getDefaultArgumentsAdjusters() {
+ return combineAdjusters(
+ getClangStripOutputAdjuster(),
+ combineAdjusters(getClangSyntaxOnlyAdjuster(),
+ getClangStripDependencyFileAdjuster()));
+}
+
+StandaloneToolExecutor::StandaloneToolExecutor(
+ const CompilationDatabase &Compilations,
+ llvm::ArrayRef<std::string> SourcePaths,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps)
+ : Tool(Compilations, SourcePaths, std::move(PCHContainerOps),
+ std::move(BaseFS)),
+ Context(&Results), ArgsAdjuster(getDefaultArgumentsAdjusters()) {
+ // Use self-defined default argument adjusters instead of the default
+ // adjusters that come with the old `ClangTool`.
+ Tool.clearArgumentsAdjusters();
+}
+
+StandaloneToolExecutor::StandaloneToolExecutor(
+ CommonOptionsParser Options,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps)
+ : OptionsParser(std::move(Options)),
+ Tool(OptionsParser->getCompilations(), OptionsParser->getSourcePathList(),
+ std::move(PCHContainerOps)),
+ Context(&Results), ArgsAdjuster(getDefaultArgumentsAdjusters()) {
+ Tool.clearArgumentsAdjusters();
+}
+
+llvm::Error StandaloneToolExecutor::execute(
+ llvm::ArrayRef<
+ std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
+ Actions) {
+ if (Actions.empty())
+ return make_string_error("No action to execute.");
+
+ if (Actions.size() != 1)
+ return make_string_error(
+ "Only support executing exactly 1 action at this point.");
+
+ auto &Action = Actions.front();
+ Tool.appendArgumentsAdjuster(Action.second);
+ Tool.appendArgumentsAdjuster(ArgsAdjuster);
+ if (Tool.run(Action.first.get()))
+ return make_string_error("Failed to run action.");
+
+ return llvm::Error::success();
+}
+
+class StandaloneToolExecutorPlugin : public ToolExecutorPlugin {
+public:
+ llvm::Expected<std::unique_ptr<ToolExecutor>>
+ create(CommonOptionsParser &OptionsParser) override {
+ if (OptionsParser.getSourcePathList().empty())
+ return make_string_error(
+ "[StandaloneToolExecutorPlugin] No positional argument found.");
+ return llvm::make_unique<StandaloneToolExecutor>(std::move(OptionsParser));
+ }
+};
+
+static ToolExecutorPluginRegistry::Add<StandaloneToolExecutorPlugin>
+ X("standalone", "Runs FrontendActions on a set of files provided "
+ "via positional arguments.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the plugin.
+volatile int StandaloneToolExecutorAnchorSource = 0;
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp
new file mode 100644
index 000000000000..63aa64a5330d
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp
@@ -0,0 +1,611 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements functions to run clang tools standalone instead
+// of running them as a plugin.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Tooling.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+#include <vector>
+
+#define DEBUG_TYPE "clang-tooling"
+
+using namespace clang;
+using namespace tooling;
+
+ToolAction::~ToolAction() = default;
+
+FrontendActionFactory::~FrontendActionFactory() = default;
+
+// FIXME: This file contains structural duplication with other parts of the
+// code that sets up a compiler to run tools on it, and we should refactor
+// it to be based on the same framework.
+
+/// Builds a clang driver initialized for running clang tools.
+static driver::Driver *
+newDriver(DiagnosticsEngine *Diagnostics, const char *BinaryName,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
+ driver::Driver *CompilerDriver =
+ new driver::Driver(BinaryName, llvm::sys::getDefaultTargetTriple(),
+ *Diagnostics, std::move(VFS));
+ CompilerDriver->setTitle("clang_based_tool");
+ return CompilerDriver;
+}
+
+/// Retrieves the clang CC1 specific flags out of the compilation's jobs.
+///
+/// Returns nullptr on error.
+static const llvm::opt::ArgStringList *getCC1Arguments(
+ DiagnosticsEngine *Diagnostics, driver::Compilation *Compilation) {
+ // We expect to get back exactly one Command job, if we didn't something
+ // failed. Extract that job from the Compilation.
+ const driver::JobList &Jobs = Compilation->getJobs();
+ if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
+ SmallString<256> error_msg;
+ llvm::raw_svector_ostream error_stream(error_msg);
+ Jobs.Print(error_stream, "; ", true);
+ Diagnostics->Report(diag::err_fe_expected_compiler_job)
+ << error_stream.str();
+ return nullptr;
+ }
+
+ // The one job we find should be to invoke clang again.
+ const auto &Cmd = cast<driver::Command>(*Jobs.begin());
+ if (StringRef(Cmd.getCreator().getName()) != "clang") {
+ Diagnostics->Report(diag::err_fe_expected_clang_command);
+ return nullptr;
+ }
+
+ return &Cmd.getArguments();
+}
+
+namespace clang {
+namespace tooling {
+
+/// Returns a clang build invocation initialized from the CC1 flags.
+CompilerInvocation *newInvocation(
+ DiagnosticsEngine *Diagnostics, const llvm::opt::ArgStringList &CC1Args) {
+ assert(!CC1Args.empty() && "Must at least contain the program name!");
+ CompilerInvocation *Invocation = new CompilerInvocation;
+ CompilerInvocation::CreateFromArgs(
+ *Invocation, CC1Args.data() + 1, CC1Args.data() + CC1Args.size(),
+ *Diagnostics);
+ Invocation->getFrontendOpts().DisableFree = false;
+ Invocation->getCodeGenOpts().DisableFree = false;
+ return Invocation;
+}
+
+bool runToolOnCode(FrontendAction *ToolAction, const Twine &Code,
+ const Twine &FileName,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
+ return runToolOnCodeWithArgs(ToolAction, Code, std::vector<std::string>(),
+ FileName, "clang-tool",
+ std::move(PCHContainerOps));
+}
+
+} // namespace tooling
+} // namespace clang
+
+static std::vector<std::string>
+getSyntaxOnlyToolArgs(const Twine &ToolName,
+ const std::vector<std::string> &ExtraArgs,
+ StringRef FileName) {
+ std::vector<std::string> Args;
+ Args.push_back(ToolName.str());
+ Args.push_back("-fsyntax-only");
+ Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
+ Args.push_back(FileName.str());
+ return Args;
+}
+
+namespace clang {
+namespace tooling {
+
+bool runToolOnCodeWithArgs(
+ FrontendAction *ToolAction, const Twine &Code,
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
+ const std::vector<std::string> &Args, const Twine &FileName,
+ const Twine &ToolName,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
+ SmallString<16> FileNameStorage;
+ StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
+
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions(), VFS));
+ ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster();
+ ToolInvocation Invocation(
+ getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef),
+ ToolAction, Files.get(),
+ std::move(PCHContainerOps));
+ return Invocation.run();
+}
+
+bool runToolOnCodeWithArgs(
+ FrontendAction *ToolAction, const Twine &Code,
+ const std::vector<std::string> &Args, const Twine &FileName,
+ const Twine &ToolName,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ const FileContentMappings &VirtualMappedFiles) {
+ llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
+ new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new llvm::vfs::InMemoryFileSystem);
+ OverlayFileSystem->pushOverlay(InMemoryFileSystem);
+
+ SmallString<1024> CodeStorage;
+ InMemoryFileSystem->addFile(FileName, 0,
+ llvm::MemoryBuffer::getMemBuffer(
+ Code.toNullTerminatedStringRef(CodeStorage)));
+
+ for (auto &FilenameWithContent : VirtualMappedFiles) {
+ InMemoryFileSystem->addFile(
+ FilenameWithContent.first, 0,
+ llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second));
+ }
+
+ return runToolOnCodeWithArgs(ToolAction, Code, OverlayFileSystem, Args,
+ FileName, ToolName);
+}
+
+llvm::Expected<std::string> getAbsolutePath(llvm::vfs::FileSystem &FS,
+ StringRef File) {
+ StringRef RelativePath(File);
+ // FIXME: Should '.\\' be accepted on Win32?
+ if (RelativePath.startswith("./")) {
+ RelativePath = RelativePath.substr(strlen("./"));
+ }
+
+ SmallString<1024> AbsolutePath = RelativePath;
+ if (auto EC = FS.makeAbsolute(AbsolutePath))
+ return llvm::errorCodeToError(EC);
+ llvm::sys::path::native(AbsolutePath);
+ return AbsolutePath.str();
+}
+
+std::string getAbsolutePath(StringRef File) {
+ return llvm::cantFail(getAbsolutePath(*llvm::vfs::getRealFileSystem(), File));
+}
+
+void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
+ StringRef InvokedAs) {
+ if (!CommandLine.empty() && !InvokedAs.empty()) {
+ bool AlreadyHasTarget = false;
+ bool AlreadyHasMode = false;
+ // Skip CommandLine[0].
+ for (auto Token = ++CommandLine.begin(); Token != CommandLine.end();
+ ++Token) {
+ StringRef TokenRef(*Token);
+ AlreadyHasTarget |=
+ (TokenRef == "-target" || TokenRef.startswith("-target="));
+ AlreadyHasMode |= (TokenRef == "--driver-mode" ||
+ TokenRef.startswith("--driver-mode="));
+ }
+ auto TargetMode =
+ driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs);
+ if (!AlreadyHasMode && TargetMode.DriverMode) {
+ CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode);
+ }
+ if (!AlreadyHasTarget && TargetMode.TargetIsValid) {
+ CommandLine.insert(++CommandLine.begin(), {"-target",
+ TargetMode.TargetPrefix});
+ }
+ }
+}
+
+} // namespace tooling
+} // namespace clang
+
+namespace {
+
+class SingleFrontendActionFactory : public FrontendActionFactory {
+ FrontendAction *Action;
+
+public:
+ SingleFrontendActionFactory(FrontendAction *Action) : Action(Action) {}
+
+ FrontendAction *create() override { return Action; }
+};
+
+} // namespace
+
+ToolInvocation::ToolInvocation(
+ std::vector<std::string> CommandLine, ToolAction *Action,
+ FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
+ : CommandLine(std::move(CommandLine)), Action(Action), OwnsAction(false),
+ Files(Files), PCHContainerOps(std::move(PCHContainerOps)) {}
+
+ToolInvocation::ToolInvocation(
+ std::vector<std::string> CommandLine, FrontendAction *FAction,
+ FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
+ : CommandLine(std::move(CommandLine)),
+ Action(new SingleFrontendActionFactory(FAction)), OwnsAction(true),
+ Files(Files), PCHContainerOps(std::move(PCHContainerOps)) {}
+
+ToolInvocation::~ToolInvocation() {
+ if (OwnsAction)
+ delete Action;
+}
+
+void ToolInvocation::mapVirtualFile(StringRef FilePath, StringRef Content) {
+ SmallString<1024> PathStorage;
+ llvm::sys::path::native(FilePath, PathStorage);
+ MappedFileContents[PathStorage] = Content;
+}
+
+bool ToolInvocation::run() {
+ std::vector<const char*> Argv;
+ for (const std::string &Str : CommandLine)
+ Argv.push_back(Str.c_str());
+ const char *const BinaryName = Argv[0];
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ unsigned MissingArgIndex, MissingArgCount;
+ std::unique_ptr<llvm::opt::OptTable> Opts = driver::createDriverOptTable();
+ llvm::opt::InputArgList ParsedArgs = Opts->ParseArgs(
+ ArrayRef<const char *>(Argv).slice(1), MissingArgIndex, MissingArgCount);
+ ParseDiagnosticArgs(*DiagOpts, ParsedArgs);
+ TextDiagnosticPrinter DiagnosticPrinter(
+ llvm::errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
+
+ const std::unique_ptr<driver::Driver> Driver(
+ 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.
+ // In this case the checks have false positives, so skip them.
+ if (!Files->getFileSystemOpts().WorkingDir.empty())
+ Driver->setCheckInputsExist(false);
+ const std::unique_ptr<driver::Compilation> Compilation(
+ Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
+ if (!Compilation)
+ return false;
+ const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
+ &Diagnostics, Compilation.get());
+ if (!CC1Args)
+ return false;
+ std::unique_ptr<CompilerInvocation> Invocation(
+ newInvocation(&Diagnostics, *CC1Args));
+ // FIXME: remove this when all users have migrated!
+ for (const auto &It : MappedFileContents) {
+ // Inject the code as the given file name into the preprocessor options.
+ std::unique_ptr<llvm::MemoryBuffer> Input =
+ llvm::MemoryBuffer::getMemBuffer(It.getValue());
+ Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(),
+ Input.release());
+ }
+ return runInvocation(BinaryName, Compilation.get(), std::move(Invocation),
+ std::move(PCHContainerOps));
+}
+
+bool ToolInvocation::runInvocation(
+ const char *BinaryName, driver::Compilation *Compilation,
+ std::shared_ptr<CompilerInvocation> Invocation,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
+ // Show the invocation, with -v.
+ if (Invocation->getHeaderSearchOpts().Verbose) {
+ llvm::errs() << "clang Invocation:\n";
+ Compilation->getJobs().Print(llvm::errs(), "\n", true);
+ llvm::errs() << "\n";
+ }
+
+ return Action->runInvocation(std::move(Invocation), Files,
+ std::move(PCHContainerOps), DiagConsumer);
+}
+
+bool FrontendActionFactory::runInvocation(
+ std::shared_ptr<CompilerInvocation> Invocation, FileManager *Files,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ DiagnosticConsumer *DiagConsumer) {
+ // Create a compiler instance to handle the actual work.
+ CompilerInstance Compiler(std::move(PCHContainerOps));
+ Compiler.setInvocation(std::move(Invocation));
+ Compiler.setFileManager(Files);
+
+ // The FrontendAction can have lifetime requirements for Compiler or its
+ // members, and we need to ensure it's deleted earlier than Compiler. So we
+ // pass it to an std::unique_ptr declared after the Compiler variable.
+ std::unique_ptr<FrontendAction> ScopedToolAction(create());
+
+ // Create the compiler's actual diagnostics engine.
+ Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
+ if (!Compiler.hasDiagnostics())
+ return false;
+
+ Compiler.createSourceManager(*Files);
+
+ const bool Success = Compiler.ExecuteAction(*ScopedToolAction);
+
+ Files->clearStatCache();
+ return Success;
+}
+
+ClangTool::ClangTool(const CompilationDatabase &Compilations,
+ ArrayRef<std::string> SourcePaths,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
+ : Compilations(Compilations), SourcePaths(SourcePaths),
+ PCHContainerOps(std::move(PCHContainerOps)),
+ OverlayFileSystem(new llvm::vfs::OverlayFileSystem(std::move(BaseFS))),
+ InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
+ Files(new FileManager(FileSystemOptions(), OverlayFileSystem)) {
+ OverlayFileSystem->pushOverlay(InMemoryFileSystem);
+ appendArgumentsAdjuster(getClangStripOutputAdjuster());
+ appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
+ appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
+}
+
+ClangTool::~ClangTool() = default;
+
+void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) {
+ MappedFileContents.push_back(std::make_pair(FilePath, Content));
+}
+
+void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) {
+ ArgsAdjuster = combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster));
+}
+
+void ClangTool::clearArgumentsAdjusters() {
+ ArgsAdjuster = nullptr;
+}
+
+static void injectResourceDir(CommandLineArguments &Args, const char *Argv0,
+ void *MainAddr) {
+ // Allow users to override the resource dir.
+ for (StringRef Arg : Args)
+ if (Arg.startswith("-resource-dir"))
+ return;
+
+ // If there's no override in place add our resource dir.
+ Args.push_back("-resource-dir=" +
+ CompilerInvocation::GetResourcesPath(Argv0, MainAddr));
+}
+
+int ClangTool::run(ToolAction *Action) {
+ // Exists solely for the purpose of lookup of the resource path.
+ // This just needs to be some symbol in the binary.
+ static int StaticSymbol;
+
+ // First insert all absolute paths into the in-memory VFS. These are global
+ // for all compile commands.
+ if (SeenWorkingDirectories.insert("/").second)
+ for (const auto &MappedFile : MappedFileContents)
+ if (llvm::sys::path::is_absolute(MappedFile.first))
+ InMemoryFileSystem->addFile(
+ MappedFile.first, 0,
+ llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
+
+ bool ProcessingFailed = false;
+ bool FileSkipped = false;
+ // Compute all absolute paths before we run any actions, as those will change
+ // the working directory.
+ std::vector<std::string> AbsolutePaths;
+ AbsolutePaths.reserve(SourcePaths.size());
+ for (const auto &SourcePath : SourcePaths) {
+ auto AbsPath = getAbsolutePath(*OverlayFileSystem, SourcePath);
+ if (!AbsPath) {
+ llvm::errs() << "Skipping " << SourcePath
+ << ". Error while getting an absolute path: "
+ << llvm::toString(AbsPath.takeError()) << "\n";
+ continue;
+ }
+ AbsolutePaths.push_back(std::move(*AbsPath));
+ }
+
+ // Remember the working directory in case we need to restore it.
+ std::string InitialWorkingDir;
+ if (RestoreCWD) {
+ if (auto CWD = OverlayFileSystem->getCurrentWorkingDirectory()) {
+ InitialWorkingDir = std::move(*CWD);
+ } else {
+ llvm::errs() << "Could not get working directory: "
+ << CWD.getError().message() << "\n";
+ }
+ }
+
+ for (llvm::StringRef File : AbsolutePaths) {
+ // Currently implementations of CompilationDatabase::getCompileCommands can
+ // change the state of the file system (e.g. prepare generated headers), so
+ // this method needs to run right before we invoke the tool, as the next
+ // file may require a different (incompatible) state of the file system.
+ //
+ // FIXME: Make the compilation database interface more explicit about the
+ // requirements to the order of invocation of its members.
+ std::vector<CompileCommand> CompileCommandsForFile =
+ Compilations.getCompileCommands(File);
+ if (CompileCommandsForFile.empty()) {
+ llvm::errs() << "Skipping " << File << ". Compile command not found.\n";
+ FileSkipped = true;
+ continue;
+ }
+ for (CompileCommand &CompileCommand : CompileCommandsForFile) {
+ // FIXME: chdir is thread hostile; on the other hand, creating the same
+ // behavior as chdir is complex: chdir resolves the path once, thus
+ // guaranteeing that all subsequent relative path operations work
+ // on the same path the original chdir resulted in. This makes a
+ // difference for example on network filesystems, where symlinks might be
+ // switched during runtime of the tool. Fixing this depends on having a
+ // file system abstraction that allows openat() style interactions.
+ if (OverlayFileSystem->setCurrentWorkingDirectory(
+ CompileCommand.Directory))
+ llvm::report_fatal_error("Cannot chdir into \"" +
+ Twine(CompileCommand.Directory) + "\n!");
+
+ // Now fill the in-memory VFS with the relative file mappings so it will
+ // have the correct relative paths. We never remove mappings but that
+ // should be fine.
+ if (SeenWorkingDirectories.insert(CompileCommand.Directory).second)
+ for (const auto &MappedFile : MappedFileContents)
+ if (!llvm::sys::path::is_absolute(MappedFile.first))
+ InMemoryFileSystem->addFile(
+ MappedFile.first, 0,
+ llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
+
+ std::vector<std::string> CommandLine = CompileCommand.CommandLine;
+ if (ArgsAdjuster)
+ CommandLine = ArgsAdjuster(CommandLine, CompileCommand.Filename);
+ assert(!CommandLine.empty());
+
+ // Add the resource dir based on the binary of this tool. argv[0] in the
+ // compilation database may refer to a different compiler and we want to
+ // pick up the very same standard library that compiler is using. The
+ // builtin headers in the resource dir need to match the exact clang
+ // version the tool is using.
+ // FIXME: On linux, GetMainExecutable is independent of the value of the
+ // first argument, thus allowing ClangTool and runToolOnCode to just
+ // pass in made-up names here. Make sure this works on other platforms.
+ injectResourceDir(CommandLine, "clang_tool", &StaticSymbol);
+
+ // FIXME: We need a callback mechanism for the tool writer to output a
+ // customized message for each file.
+ LLVM_DEBUG({ llvm::dbgs() << "Processing: " << File << ".\n"; });
+ ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(),
+ PCHContainerOps);
+ Invocation.setDiagnosticConsumer(DiagConsumer);
+
+ if (!Invocation.run()) {
+ // FIXME: Diagnostics should be used instead.
+ llvm::errs() << "Error while processing " << File << ".\n";
+ ProcessingFailed = true;
+ }
+ }
+ }
+
+ if (!InitialWorkingDir.empty()) {
+ if (auto EC =
+ OverlayFileSystem->setCurrentWorkingDirectory(InitialWorkingDir))
+ llvm::errs() << "Error when trying to restore working dir: "
+ << EC.message() << "\n";
+ }
+ return ProcessingFailed ? 1 : (FileSkipped ? 2 : 0);
+}
+
+namespace {
+
+class ASTBuilderAction : public ToolAction {
+ std::vector<std::unique_ptr<ASTUnit>> &ASTs;
+
+public:
+ ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &ASTs) : ASTs(ASTs) {}
+
+ bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
+ FileManager *Files,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ DiagnosticConsumer *DiagConsumer) override {
+ std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
+ Invocation, std::move(PCHContainerOps),
+ CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts(),
+ DiagConsumer,
+ /*ShouldOwnClient=*/false),
+ Files);
+ if (!AST)
+ return false;
+
+ ASTs.push_back(std::move(AST));
+ return true;
+ }
+};
+
+} // namespace
+
+int ClangTool::buildASTs(std::vector<std::unique_ptr<ASTUnit>> &ASTs) {
+ ASTBuilderAction Action(ASTs);
+ return run(&Action);
+}
+
+void ClangTool::setRestoreWorkingDir(bool RestoreCWD) {
+ this->RestoreCWD = RestoreCWD;
+}
+
+namespace clang {
+namespace tooling {
+
+std::unique_ptr<ASTUnit>
+buildASTFromCode(StringRef Code, StringRef FileName,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
+ return buildASTFromCodeWithArgs(Code, std::vector<std::string>(), FileName,
+ "clang-tool", std::move(PCHContainerOps));
+}
+
+std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
+ StringRef Code, const std::vector<std::string> &Args, StringRef FileName,
+ StringRef ToolName, std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ ArgumentsAdjuster Adjuster) {
+ std::vector<std::unique_ptr<ASTUnit>> ASTs;
+ ASTBuilderAction Action(ASTs);
+ llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
+ new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new llvm::vfs::InMemoryFileSystem);
+ OverlayFileSystem->pushOverlay(InMemoryFileSystem);
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions(), OverlayFileSystem));
+
+ ToolInvocation Invocation(
+ getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileName), FileName),
+ &Action, Files.get(), std::move(PCHContainerOps));
+
+ InMemoryFileSystem->addFile(FileName, 0,
+ llvm::MemoryBuffer::getMemBufferCopy(Code));
+ if (!Invocation.run())
+ return nullptr;
+
+ assert(ASTs.size() == 1);
+ return std::move(ASTs[0]);
+}
+
+} // namespace tooling
+} // namespace clang