Skip to content

Commit 1c0b15c

Browse files
committed
Add support for renaming local variables inside functions
1 parent 3ff0f7b commit 1c0b15c

File tree

5 files changed

+129
-2
lines changed

5 files changed

+129
-2
lines changed

src/main/QafooLabs/Refactoring/Adapters/TokenReflection/StaticCodeAnalysis.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,28 @@ public function getMethodStartLine(File $file, LineRange $range)
6262
return $method->getStartLine();
6363
}
6464

65+
public function getFunctionEndLine(File $file, LineRange $range)
66+
{
67+
$function = $this->findMatchingFunction($file, $range);
68+
69+
if ($function === null) {
70+
throw new \InvalidArgumentException("Could not find function end line.");
71+
}
72+
73+
return $function->getEndLine();
74+
}
75+
76+
public function getFunctionStartLine(File $file, LineRange $range)
77+
{
78+
$function = $this->findMatchingFunction($file, $range);
79+
80+
if ($function === null) {
81+
throw new \InvalidArgumentException("Could not find function start line.");
82+
}
83+
84+
return $function->getStartLine();
85+
}
86+
6587
public function getLineOfLastPropertyDefinedInScope(File $file, $lastLine)
6688
{
6789
$this->broker = new Broker(new Memory);
@@ -91,6 +113,16 @@ public function isInsideMethod(File $file, LineRange $range)
91113
return $this->findMatchingMethod($file, $range) !== null;
92114
}
93115

116+
public function isInsideFunction(File $file, LineRange $range)
117+
{
118+
return $this->findMatchingFunction($file, $range) !== null;
119+
}
120+
121+
public function isLocalScope(File $file, LineRange $range)
122+
{
123+
return $this->isInsideMethod($file, $range) || $this->isInsideFunction($file, $range);
124+
}
125+
94126
/**
95127
* @param File $file
96128
* @return PhpClass[]
@@ -137,4 +169,24 @@ private function findMatchingMethod(File $file, LineRange $range)
137169

138170
return $foundMethod;
139171
}
172+
173+
private function findMatchingFunction(File $file, LineRange $range)
174+
{
175+
$foundFunction = null;
176+
177+
$this->broker = new Broker(new Memory);
178+
$file = $this->broker->processString($file->getCode(), $file->getRelativePath(), true);
179+
$lastLine = $range->getEnd();
180+
181+
foreach ($file->getNamespaces() as $namespace) {
182+
foreach ($namespace->getFunctions() as $function) {
183+
if ($function->getStartLine() < $lastLine && $lastLine < $function->getEndLine()) {
184+
$foundFunction = $function;
185+
break;
186+
}
187+
}
188+
}
189+
190+
return $foundFunction;
191+
}
140192
}

src/main/QafooLabs/Refactoring/Application/RenameLocalVariable.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function refactor(File $file, $line, Variable $oldName, Variable $newName
3939
$this->newName = $newName;
4040
$this->oldName = $oldName;
4141

42-
$this->assertIsInsideMethod();
42+
$this->assertIsLocalScope();
4343

4444
$this->assertVariableIsLocal($this->oldName);
4545
$this->assertVariableIsLocal($this->newName);

src/main/QafooLabs/Refactoring/Application/SingleFileRefactoring.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ protected function assertIsInsideMethod()
5959
}
6060
}
6161

62+
protected function assertIsLocalScope()
63+
{
64+
if ( ! $this->codeAnalysis->isLocalScope($this->file, LineRange::fromSingleLine($this->line)) ) {
65+
throw RefactoringException::rangeIsNotLocalScope(LineRange::fromSingleLine($this->line));
66+
}
67+
}
68+
6269
protected function startEditingSession()
6370
{
6471
$buffer = $this->editor->openBuffer($this->file);
@@ -75,7 +82,11 @@ protected function completeEditingSession()
7582

7683
protected function getDefinedVariables()
7784
{
78-
$selectedMethodLineRange = $this->codeAnalysis->findMethodRange($this->file, LineRange::fromSingleLine($this->line));
85+
if ($this->codeAnalysis->isInsideFunction($this->file, LineRange::fromSingleLine($this->line))) {
86+
$selectedMethodLineRange = $this->codeAnalysis->findFunctionRange($this->file, LineRange::fromSingleLine($this->line));
87+
} else {
88+
$selectedMethodLineRange = $this->codeAnalysis->findMethodRange($this->file, LineRange::fromSingleLine($this->line));
89+
}
7990

8091
$definedVariables = $this->variableScanner->scanForVariables(
8192
$this->file, $selectedMethodLineRange

src/main/QafooLabs/Refactoring/Domain/Model/RefactoringException.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,12 @@ static public function rangeIsNotInsideMethod(LineRange $range)
4545
$range->getStart(), $range->getEnd()
4646
));
4747
}
48+
49+
static public function rangeIsNotLocalScope(LineRange $range)
50+
{
51+
return new self(sprintf(
52+
'The range %d-%d is not inside a method or a function.',
53+
$range->getStart(), $range->getEnd()
54+
));
55+
}
4856
}

src/main/QafooLabs/Refactoring/Domain/Services/CodeAnalysis.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,42 @@ abstract public function getMethodStartLine(File $file, LineRange $range);
4040
*/
4141
abstract public function getMethodEndLine(File $file, LineRange $range);
4242

43+
/**
44+
* Get the function start line
45+
*
46+
* @param File $file
47+
* @param LineRange $range
48+
*
49+
* @return int
50+
*/
51+
abstract public function getFunctionStartLine(File $file, LineRange $range);
52+
53+
/**
54+
* Get the function end line
55+
*
56+
* @param File $file
57+
* @param LineRange $range
58+
*
59+
* @return int
60+
*/
61+
abstract public function getFunctionEndLine(File $file, LineRange $range);
62+
4363
/**
4464
* @param File $file
4565
* @param int $line
4666
*/
4767
abstract public function getLineOfLastPropertyDefinedInScope(File $file, $line);
4868

69+
/**
70+
* Check if the line range is inside a local scope. A local scope being a method or a function.
71+
*
72+
* @param File $file
73+
* @param LineRange $range
74+
*
75+
* @return bool
76+
*/
77+
abstract public function isLocalScope(File $file, LineRange $range);
78+
4979
/**
5080
* Check if the line range is inside exactly one class method.
5181
*
@@ -56,6 +86,16 @@ abstract public function getLineOfLastPropertyDefinedInScope(File $file, $line);
5686
*/
5787
abstract public function isInsideMethod(File $file, LineRange $range);
5888

89+
/**
90+
* Check if the line range is inside a function.
91+
*
92+
* @param File $file
93+
* @param LineRange $range
94+
*
95+
* @return bool
96+
*/
97+
abstract public function isInsideFunction(File $file, LineRange $range);
98+
5999
/**
60100
* Find all classes in the file.
61101
*
@@ -79,5 +119,21 @@ public function findMethodRange(File $file, LineRange $range)
79119

80120
return LineRange::fromLines($methodStartLine, $methodEndLine);
81121
}
122+
123+
/**
124+
* From a range within a method, find the start and end range of that method.
125+
*
126+
* @param File $file
127+
* @param LineRange $range
128+
*
129+
* @return LineRange
130+
*/
131+
public function findFunctionRange(File $file, LineRange $range)
132+
{
133+
$methodStartLine = $this->getFunctionStartLine($file, $range);
134+
$methodEndLine = $this->getFunctionEndLine($file, $range);
135+
136+
return LineRange::fromLines($methodStartLine, $methodEndLine);
137+
}
82138
}
83139

0 commit comments

Comments
 (0)