Skip to content

Commit aa769f0

Browse files
author
Игнат Сергеев
committed
Add source location argument
Added source location argument for clang-refactor cli
1 parent d631dae commit aa769f0

File tree

1 file changed

+143
-6
lines changed

1 file changed

+143
-6
lines changed

clang/tools/clang-refactor/ClangRefactor.cpp

Lines changed: 143 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,85 @@ SourceSelectionArgument::fromString(StringRef Value) {
164164
return nullptr;
165165
}
166166

167+
/// Stores the parsed `-location` argument.
168+
class AbstractSourceLocationArgument {
169+
public:
170+
virtual ~AbstractSourceLocationArgument() {}
171+
172+
/// Parse the `-location` argument.
173+
///
174+
/// \returns A valid argument when the parse succedeed, null otherwise.
175+
static std::unique_ptr<AbstractSourceLocationArgument>
176+
fromString(StringRef Value);
177+
178+
/// Prints any additional state associated with the location argument to
179+
/// the given output stream.
180+
virtual void print(raw_ostream &OS) {}
181+
182+
/// Returns a replacement refactoring result consumer (if any) that should
183+
/// consume the results of a refactoring operation.
184+
///
185+
/// The replacement refactoring result consumer is used by \c
186+
/// TestSourceLocationArgument to inject a test-specific result handling
187+
/// logic into the refactoring operation. The test-specific consumer
188+
/// ensures that the individual results in a particular test group are
189+
/// identical.
190+
virtual std::unique_ptr<ClangRefactorToolConsumerInterface>
191+
createCustomConsumer() {
192+
return nullptr;
193+
}
194+
195+
/// Runs the given refactoring function for each specified location.
196+
///
197+
/// \returns true if an error occurred, false otherwise.
198+
virtual bool
199+
forAllLocations(const SourceManager &SM,
200+
llvm::function_ref<void(SourceLocation L)> Callback) = 0;
201+
};
202+
203+
/// Stores the parsed -location=filename:line:column option.
204+
class SourceLocationArgument final : public AbstractSourceLocationArgument {
205+
public:
206+
SourceLocationArgument(ParsedSourceLocation Location)
207+
: Location(std::move(Location)) {}
208+
209+
bool forAllLocations(
210+
const SourceManager &SM,
211+
llvm::function_ref<void(SourceLocation L)> Callback) override {
212+
auto FE = SM.getFileManager().getFile(Location.FileName);
213+
FileID FID = FE ? SM.translateFile(*FE) : FileID();
214+
if (!FE || FID.isInvalid()) {
215+
llvm::errs() << "error: -location=" << Location.FileName
216+
<< ":... : given file is not in the target TU\n";
217+
return true;
218+
}
219+
220+
SourceLocation Loc = SM.getMacroArgExpandedLocation(
221+
SM.translateLineCol(FID, Location.Line, Location.Column));
222+
if (Loc.isInvalid()) {
223+
llvm::errs() << "error: -location=" << Location.FileName << ':'
224+
<< Location.Line << ':' << Location.Column
225+
<< " : invalid source location\n";
226+
return true;
227+
}
228+
Callback(Loc);
229+
return false;
230+
}
231+
232+
private:
233+
ParsedSourceLocation Location;
234+
};
235+
236+
std::unique_ptr<AbstractSourceLocationArgument>
237+
AbstractSourceLocationArgument::fromString(StringRef Value) {
238+
ParsedSourceLocation Location = ParsedSourceLocation::FromString(Value);
239+
if (Location.FileName != "")
240+
return std::make_unique<SourceLocationArgument>(std::move(Location));
241+
llvm::errs() << "error: '-location' option must be specified using "
242+
"<file>:<line>:<column>\n";
243+
return nullptr;
244+
}
245+
167246
/// A container that stores the command-line options used by a single
168247
/// refactoring option.
169248
class RefactoringActionCommandLineOptions {
@@ -272,6 +351,17 @@ class RefactoringActionSubcommand : public cl::SubCommand {
272351
break;
273352
}
274353
}
354+
// Check if the location option is supported.
355+
for (const auto &Rule : this->ActionRules) {
356+
if (Rule->hasLocationRequirement()) {
357+
Location = std::make_unique<cl::opt<std::string>>(
358+
"location",
359+
cl::desc("Location where refactoring should "
360+
"be initiated( <file>:<line>:<column>)"),
361+
cl::cat(Category), cl::sub(*this));
362+
break;
363+
}
364+
}
275365
// Create the refactoring options.
276366
for (const auto &Rule : this->ActionRules) {
277367
CommandLineRefactoringOptionCreator OptionCreator(Category, *this,
@@ -296,11 +386,28 @@ class RefactoringActionSubcommand : public cl::SubCommand {
296386
return false;
297387
}
298388

389+
/// Parses the "-location" command-line argument.
390+
///
391+
/// \returns true on error, false otherwise.
392+
bool parseLocationArgument() {
393+
if (Location) {
394+
ParsedLocation = AbstractSourceLocationArgument::fromString(*Location);
395+
if (!ParsedLocation)
396+
return true;
397+
}
398+
return false;
399+
}
400+
299401
SourceSelectionArgument *getSelection() const {
300402
assert(Selection && "selection not supported!");
301403
return ParsedSelection.get();
302404
}
303405

406+
AbstractSourceLocationArgument *getLocation() const {
407+
assert(Location && "location not supported!");
408+
return ParsedLocation.get();
409+
}
410+
304411
const RefactoringActionCommandLineOptions &getOptions() const {
305412
return Options;
306413
}
@@ -309,7 +416,9 @@ class RefactoringActionSubcommand : public cl::SubCommand {
309416
std::unique_ptr<RefactoringAction> Action;
310417
RefactoringActionRules ActionRules;
311418
std::unique_ptr<cl::opt<std::string>> Selection;
419+
std::unique_ptr<cl::opt<std::string>> Location;
312420
std::unique_ptr<SourceSelectionArgument> ParsedSelection;
421+
std::unique_ptr<AbstractSourceLocationArgument> ParsedLocation;
313422
RefactoringActionCommandLineOptions Options;
314423
};
315424

@@ -399,6 +508,7 @@ class ClangRefactorTool {
399508
// consumer.
400509
std::unique_ptr<ClangRefactorToolConsumerInterface> TestConsumer;
401510
bool HasSelection = MatchingRule->hasSelectionRequirement();
511+
bool HasLocation = MatchingRule->hasLocationRequirement();
402512
if (HasSelection)
403513
TestConsumer = SelectedSubcommand->getSelection()->createCustomConsumer();
404514
ClangRefactorToolConsumerInterface *ActiveConsumer =
@@ -424,6 +534,19 @@ class ClangRefactorTool {
424534
ActiveConsumer->endTU();
425535
return;
426536
}
537+
if (HasLocation) {
538+
assert(SelectedSubcommand->getLocation() && "Missing location argument?");
539+
if (opts::Verbose)
540+
SelectedSubcommand->getLocation()->print(llvm::outs());
541+
if (SelectedSubcommand->getLocation()->forAllLocations(
542+
Context.getSources(), [&](SourceLocation L) {
543+
Context.setLocation(L);
544+
InvokeRule(*ActiveConsumer);
545+
}))
546+
HasFailed = true;
547+
ActiveConsumer->endTU();
548+
return;
549+
}
427550
InvokeRule(*ActiveConsumer);
428551
ActiveConsumer->endTU();
429552
}
@@ -528,6 +651,12 @@ class ClangRefactorTool {
528651
R.getEnd().print(llvm::outs(), Context.getSources());
529652
llvm::outs() << "\n";
530653
}
654+
if (Context.getLocation().isValid()) {
655+
SourceLocation L = Context.getLocation();
656+
llvm::outs() << " -location=";
657+
L.print(llvm::outs(), Context.getSources());
658+
llvm::outs() << "\n";
659+
}
531660
}
532661

533662
llvm::Expected<RefactoringActionRule *>
@@ -539,16 +668,24 @@ class ClangRefactorTool {
539668
CommandLineRefactoringOptionVisitor Visitor(Subcommand.getOptions());
540669
Rule->visitRefactoringOptions(Visitor);
541670
if (Visitor.getMissingRequiredOptions().empty()) {
542-
if (!Rule->hasSelectionRequirement()) {
543-
MatchingRules.push_back(Rule.get());
544-
} else {
671+
bool HasMissingOptions = false;
672+
if (Rule->hasSelectionRequirement()) {
545673
Subcommand.parseSelectionArgument();
546-
if (Subcommand.getSelection()) {
547-
MatchingRules.push_back(Rule.get());
548-
} else {
674+
if (!Subcommand.getSelection()) {
549675
MissingOptions.insert("selection");
676+
HasMissingOptions = true;
550677
}
551678
}
679+
if (Rule->hasLocationRequirement()) {
680+
Subcommand.parseLocationArgument();
681+
if (!Subcommand.getLocation()) {
682+
MissingOptions.insert("location");
683+
HasMissingOptions = true;
684+
}
685+
}
686+
if (!HasMissingOptions) {
687+
MatchingRules.push_back(Rule.get());
688+
}
552689
}
553690
for (const RefactoringOption *Opt : Visitor.getMissingRequiredOptions())
554691
MissingOptions.insert(Opt->getName());

0 commit comments

Comments
 (0)