Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticRefactoringKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ def err_refactor_extract_simple_expression : Error<"the selected expression "
def err_refactor_extract_prohibited_expression : Error<"the selected "
"expression can't be extracted">;

def err_refactor_no_location : Error<"refactoring action can't be initiated "
"without a location">;
def err_refactor_location_no_statement : Error<"the provided location is not "
"surrouded by an AST statement">;
}

} // end of Refactoring diagnostics
30 changes: 30 additions & 0 deletions clang/include/clang/Tooling/Refactoring/ASTStatement.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===--- ASTStatement.h - Clang refactoring library -----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLING_REFACTORING_ASTSTATEMENT_H
#define LLVM_CLANG_TOOLING_REFACTORING_ASTSTATEMENT_H

#include "clang/AST/Stmt.h"
#include "clang/Basic/SourceLocation.h"

namespace clang {

class ASTContext;

namespace tooling {

/// Traverses the given ASTContext and finds closest outer statement.
///
/// \returns nullptr if location is not surrounded by any statement, or a AST
/// statement otherwise.
Stmt *findOuterStmt(const ASTContext &Context,
SourceLocation Location);
} // end namespace tooling
} // end namespace clang

#endif // LLVM_CLANG_TOOLING_REFACTORING_ASTSTATEMENT_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===--- DeleteStatementRule.h - Clang refactoring library ----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLING_REFACTORING_DELETE_DELETESTATEMENTRULE_H
#define LLVM_CLANG_TOOLING_REFACTORING_DELETE_DELETESTATEMENTRULE_H

#include "clang/Tooling/Refactoring/RefactoringActionRules.h"

namespace clang {
namespace tooling {

/// A "Delete Statement" refactoring rule deletes code around given statement
class DeleteStatementRule final : public SourceChangeRefactoringRule {
public:
/// Initiates the delete statement refactoring operation.
///
/// \param Statement Statement to delete.
static Expected<DeleteStatementRule>
initiate(RefactoringRuleContext &Context, Stmt *Stmt);

static const RefactoringDescriptor &describe();

private:
DeleteStatementRule(Stmt *Stmt)
: Statement(std::move(Stmt)) {}

Expected<AtomicChanges>
createSourceReplacements(RefactoringRuleContext &Context) override;

Stmt *Statement;
};

} // end namespace tooling
} // end namespace clang

#endif // LLVM_CLANG_TOOLING_REFACTORING_DELETE_DELETESTATEMENTRULE_H
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ class RefactoringActionRule : public RefactoringActionRuleBase {
/// to be fulfilled before refactoring can be performed.
virtual bool hasSelectionRequirement() = 0;

/// Returns true when the rule has a source location requirement that has
/// to be fulfilled before refactoring can be performed.
virtual bool hasLocationRequirement() = 0;

/// Traverses each refactoring option used by the rule and invokes the
/// \c visit callback in the consumer for each option.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGACTIONRULEREQUIREMENTS_H

#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Tooling/Refactoring/ASTSelection.h"
#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
#include "clang/Tooling/Refactoring/RefactoringOption.h"
Expand Down Expand Up @@ -77,6 +78,25 @@ class CodeRangeASTSelectionRequirement : public ASTSelectionRequirement {
evaluate(RefactoringRuleContext &Context) const;
};

/// A base class for any requirement that expects source code position (or the refactoring tool with the -location option).
class SourceLocationRequirement : public RefactoringActionRuleRequirement {
public:
Expected<SourceLocation> evaluate(RefactoringRuleContext &Context) const {
if (Context.getLocation().isValid())
return Context.getLocation();
return Context.createDiagnosticError(diag::err_refactor_no_location);
}
};

/// An AST statement requirement is satisfied when location is surrounded by statement.
///
/// The requirement will be evaluated only once during the initiation and
/// search of matching refactoring action rules.
class ASTStatementRequirement : public SourceLocationRequirement {
public:
Expected<Stmt *> evaluate(RefactoringRuleContext &Context) const;
};

/// A base class for any requirement that requires some refactoring options.
class RefactoringOptionsRequirement : public RefactoringActionRuleRequirement {
public:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ createRefactoringActionRule(const RequirementTypes &... Requirements) {
RequirementTypes...>::value;
}

bool hasLocationRequirement() override {
return internal::HasBaseOf<SourceLocationRequirement,
RequirementTypes...>::value;
}

void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override {
internal::visitRefactoringOptions(
Visitor, Requirements,
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ namespace tooling {
///
/// - SelectionRange: an optional source selection ranges that can be used
/// to represent a selection in an editor.
///
/// - Location: an optional source location that can be used
/// to represent a cursor in an editor.
class RefactoringRuleContext {
public:
RefactoringRuleContext(const SourceManager &SM) : SM(SM) {}
Expand All @@ -40,8 +43,14 @@ class RefactoringRuleContext {
/// refactoring engine. Can be invalid.
SourceRange getSelectionRange() const { return SelectionRange; }

/// Returns the current source location as set by the
/// refactoring engine. Can be invalid.
SourceLocation getLocation() const { return Location; }

void setSelectionRange(SourceRange R) { SelectionRange = R; }

void setLocation(SourceLocation L) { Location = L; }

bool hasASTContext() const { return AST; }

ASTContext &getASTContext() const {
Expand Down Expand Up @@ -73,6 +82,9 @@ class RefactoringRuleContext {
/// An optional source selection range that's commonly used to represent
/// a selection in an editor.
SourceRange SelectionRange;
/// An optional source location that's commonly used to represent
/// a cursor in an editor.
SourceLocation Location;
/// An optional AST for the translation unit on which a refactoring action
/// might operate on.
ASTContext *AST = nullptr;
Expand Down
58 changes: 58 additions & 0 deletions clang/lib/Tooling/Refactoring/ASTStatement.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//===--- ASTStatement.cpp - Clang refactoring library ---------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/Tooling/Refactoring/ASTStatement.h"
#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"

using namespace clang;
using namespace tooling;

namespace {

class ASTStatementFinder
: public LexicallyOrderedRecursiveASTVisitor<ASTStatementFinder> {
public:
ASTStatementFinder(SourceLocation Location, FileID TargetFile,
const ASTContext &Context)
: LexicallyOrderedRecursiveASTVisitor(Context.getSourceManager()),
Location(std::move(Location)),
TargetFile(TargetFile), Context(Context) {}

bool TraverseStmt(Stmt *Statement) {
if (!Statement)
return true;
const SourceManager &SM = Context.getSourceManager();
if (SM.isPointWithin(Location, Statement->getBeginLoc(), Statement->getEndLoc())) {
this->Statement = Statement;
}
LexicallyOrderedRecursiveASTVisitor::TraverseStmt(Statement);
return true;
}

Stmt *getOuterStatement() {
return Statement;
}
private:
const SourceLocation Location;
FileID TargetFile;
const ASTContext &Context;
Stmt *Statement = nullptr;
};

} // end anonymous namespace

Stmt *
clang::tooling::findOuterStmt(const ASTContext &Context, SourceLocation Location) {
assert(Location.isValid() && Location.isFileID() && "Expected a file location");

FileID TargetFile = Context.getSourceManager().getFileID(Location);

ASTStatementFinder Visitor(Location, TargetFile, Context);
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
return Visitor.getOuterStatement();
}
28 changes: 28 additions & 0 deletions clang/lib/Tooling/Refactoring/ASTStatementRequirements.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===--- ASTStatementRequirements.cpp - Clang refactoring library ---------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
#include "clang/Tooling/Refactoring/ASTStatement.h"

using namespace clang;
using namespace tooling;

Expected<Stmt *>
ASTStatementRequirement::evaluate(RefactoringRuleContext &Context) const {
Expected<SourceLocation> Location =
SourceLocationRequirement::evaluate(Context);
if (!Location)
return Location.takeError();

Stmt *Statement =
findOuterStmt(Context.getASTContext(), *Location);
if (Statement == nullptr)
return Context.createDiagnosticError(
*Location, diag::err_refactor_location_no_statement);
return std::move(Statement);
}
3 changes: 3 additions & 0 deletions clang/lib/Tooling/Refactoring/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ set(LLVM_LINK_COMPONENTS Support)
add_clang_library(clangToolingRefactoring
ASTSelection.cpp
ASTSelectionRequirements.cpp
ASTStatement.cpp
ASTStatementRequirements.cpp
AtomicChange.cpp
Extract/Extract.cpp
Extract/SourceExtraction.cpp
Expand All @@ -13,6 +15,7 @@ add_clang_library(clangToolingRefactoring
Rename/USRFinder.cpp
Rename/USRFindingAction.cpp
Rename/USRLocFinder.cpp
Delete/DeleteStatementRule.cpp

LINK_LIBS
clangAST
Expand Down
62 changes: 62 additions & 0 deletions clang/lib/Tooling/Refactoring/Delete/DeleteStatementRule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//===--- DeleteStatementRule.cpp - Clang refactoring library --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Implements the "delete-statement" refactoring rule that can delete stmts
///
//===----------------------------------------------------------------------===//

#include "clang/Tooling/Refactoring/ASTStatement.h"
#include "clang/Tooling/Refactoring/Delete/DeleteStatementRule.h"
#include "clang/AST/ASTContext.h"
#include "clang/Rewrite/Core/Rewriter.h"

using namespace clang;
using namespace tooling;

Expected<DeleteStatementRule>
DeleteStatementRule::initiate(RefactoringRuleContext &Context, Stmt *Stmt) {
return DeleteStatementRule(std::move(Stmt));
}

const RefactoringDescriptor &DeleteStatementRule::describe() {
static const RefactoringDescriptor Descriptor = {
"delete-statement",
"Delete Statement",
"Deletes stmts from code",
};
return Descriptor;
}

Expected<AtomicChanges>
DeleteStatementRule::createSourceReplacements(RefactoringRuleContext &Context) {
// Compute the source range of the code that should be deleted.
SourceRange DeleteRange(Statement->getBeginLoc(),
Statement->getEndLoc());

ASTContext &AST = Context.getASTContext();
SourceManager &SM = AST.getSourceManager();
const LangOptions &LangOpts = AST.getLangOpts();
Rewriter DeleteCodeRewriter(SM, LangOpts);

PrintingPolicy PP = AST.getPrintingPolicy();
PP.SuppressStrongLifetime = true;
PP.SuppressLifetimeQualifiers = true;
PP.SuppressUnwrittenScope = true;

AtomicChange Change(SM, Statement->getBeginLoc());
// Create the replacement for deleting statement
{
auto Err = Change.replace(
SM, CharSourceRange::getTokenRange(DeleteRange), "");
if (Err)
return std::move(Err);
}

return AtomicChanges{std::move(Change)};
}
Loading