Skip to content

Commit 9a1810a

Browse files
committed
More tests for FieldFromParameter generator job.
Fixed cases with super constructor calls, it was never completely right. Removed the extra check super method calls, because that one is different, and other IDEs don't treat it differently. A bit more sensible indentation when getting the function body insertion point.
1 parent 0499945 commit 9a1810a

11 files changed

+483
-121
lines changed

External/Plugins/ASCompletion/Completion/ASGenerator.cs

Lines changed: 140 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class ASGenerator
3232
const string NewLine = "$(Boundary)\n";
3333
static private Regex reModifiers = new Regex("^\\s*(\\$\\(Boundary\\))?([a-z ]+)(function|var|const)", RegexOptions.Compiled);
3434
static private Regex reModifier = new Regex("(public |private |protected )", RegexOptions.Compiled);
35+
static private Regex reSuperCall = new Regex("^super\\s*\\(", RegexOptions.Compiled);
3536

3637
static private string contextToken;
3738
static private string contextParam;
@@ -1741,26 +1742,22 @@ private static void AddInterfaceDefJob(ClassModel inClass, ScintillaControl sci,
17411742
private static void GenerateFieldFromParameter(ScintillaControl sci, MemberModel member, ClassModel inClass,
17421743
Visibility scope)
17431744
{
1744-
int funcBodyStart = GetBodyStart(member.LineFrom, member.LineTo, sci);
1745+
int funcBodyStart = GetBodyStart(member.LineFrom, member.LineTo, sci, false);
1746+
int fbsLine = sci.LineFromPosition(funcBodyStart);
1747+
int endPos = sci.LineEndPosition(member.LineTo);
17451748

1746-
sci.SetSel(funcBodyStart, sci.LineEndPosition(member.LineTo));
1749+
sci.SetSel(funcBodyStart, endPos);
17471750
string body = sci.SelText;
17481751
string trimmed = body.TrimStart();
17491752

1750-
Regex re = new Regex("^super\\s*[\\(|\\.]");
1751-
Match m = re.Match(trimmed);
1752-
if (m.Success)
1753+
Match m = reSuperCall.Match(trimmed);
1754+
if (m.Success && m.Index == 0)
17531755
{
1754-
if (m.Index == 0)
1755-
{
1756-
int p = funcBodyStart + (body.Length - trimmed.Length);
1757-
int l = sci.LineFromPosition(p);
1758-
p = sci.PositionFromLine(l + 1);
1759-
throw new NotImplementedException("reimplement");
1760-
//funcBodyStart = GetBodyStart(member.LineFrom, member.LineTo, sci, p);
1761-
}
1756+
funcBodyStart = GetEndOfStatement(funcBodyStart + (body.Length - trimmed.Length), endPos, sci);
17621757
}
17631758

1759+
funcBodyStart = GetOrSetPointOfInsertion(funcBodyStart, endPos, fbsLine, sci);
1760+
17641761
sci.SetSel(funcBodyStart, funcBodyStart);
17651762
sci.CurrentPos = funcBodyStart;
17661763

@@ -1797,8 +1794,6 @@ private static void GenerateFieldFromParameter(ScintillaControl sci, MemberModel
17971794
}
17981795
}
17991796

1800-
1801-
18021797
string template = TemplateUtils.GetTemplate("FieldFromParameter");
18031798
template = TemplateUtils.ReplaceTemplateVariable(template, "Name", scopedVarName);
18041799
template = TemplateUtils.ReplaceTemplateVariable(template, "Value", paramName);
@@ -1830,87 +1825,187 @@ private static void GenerateFieldFromParameter(ScintillaControl sci, MemberModel
18301825
/// <summary>
18311826
/// Tries to get the best position inside a code block, delimited by { and }, to add new code, inserting new lines if needed.
18321827
/// </summary>
1833-
/// <param name="lineFrom">The line inside the scintilla document where the owner member of the body starts</param>
1834-
/// <param name="lineTo">The line inside the scintilla document where the owner member of the body ends</param>
1835-
/// <param name="Sci">The Scintilla control containing the document</param>
1828+
/// <param name="lineFrom">The line inside the Scintilla document where the owner member of the body starts</param>
1829+
/// <param name="lineTo">The line inside the Scintilla document where the owner member of the body ends</param>
1830+
/// <param name="sci">The Scintilla control containing the document</param>
18361831
/// <returns>The position inside the scintilla document, or -1 if not suitable position was found</returns>
1837-
public static int GetBodyStart(int lineFrom, int lineTo, ScintillaControl Sci)
1832+
public static int GetBodyStart(int lineFrom, int lineTo, ScintillaControl sci)
18381833
{
1839-
int posStart = Sci.PositionFromLine(lineFrom);
1840-
int posEnd = Sci.LineEndPosition(lineTo);
1834+
return GetBodyStart(lineFrom, lineTo, sci, true);
1835+
}
1836+
1837+
/// <summary>
1838+
/// Tries to get the start position of a code block, delimited by { and }
1839+
/// </summary>
1840+
/// <param name="lineFrom">The line inside the Scintilla document where the owner member of the body starts</param>
1841+
/// <param name="lineTo">The line inside the Scintilla document where the owner member of the body ends</param>
1842+
/// <param name="sci">The Scintilla control containing the document</param>
1843+
/// <param name="needsPointOfInsertion">If true looks for the position to add new code, inserting new lines if needed</param>
1844+
/// <returns>The position inside the Scintilla document, or -1 if not suitable position was found</returns>
1845+
public static int GetBodyStart(int lineFrom, int lineTo, ScintillaControl sci, bool needsPointOfInsertion)
1846+
{
1847+
int posStart = sci.PositionFromLine(lineFrom);
1848+
int posEnd = sci.LineEndPosition(lineTo);
18411849

1842-
char[] characterClass = new[] { ' ', '\r', '\n', '\t' };
1843-
int nCount = 0;
18441850
int funcBodyStart = -1;
1845-
int extraLine = 1;
18461851

18471852
int genCount = 0;
18481853
for (int i = posStart; i <= posEnd; i++)
18491854
{
1850-
char c = (char)Sci.CharAt(i);
1855+
char c = (char)sci.CharAt(i);
18511856

18521857
if (c == '{')
18531858
{
1854-
int style = Sci.BaseStyleAt(i);
1859+
int style = sci.BaseStyleAt(i);
18551860
if (ASComplete.IsCommentStyle(style) || ASComplete.IsLiteralStyle(style) || genCount > 0)
18561861
continue;
18571862
funcBodyStart = i;
18581863
break;
18591864
}
18601865
else if (c == '<')
18611866
{
1862-
int style = Sci.BaseStyleAt(i);
1867+
int style = sci.BaseStyleAt(i);
18631868
if (style == 10)
18641869
genCount++;
18651870
}
18661871
else if (c == '>')
18671872
{
1868-
int style = Sci.BaseStyleAt(i);
1873+
int style = sci.BaseStyleAt(i);
18691874
if (style == 10)
18701875
genCount--;
18711876
}
18721877
}
18731878

18741879
if (funcBodyStart == -1)
1875-
return -1;
1880+
return -1;
1881+
1882+
if (needsPointOfInsertion)
1883+
{
1884+
int ln = sci.LineFromPosition(funcBodyStart);
18761885

1877-
int ln = Sci.LineFromPosition(funcBodyStart);
1878-
int indent = Sci.GetLineIndentation(ln);
1879-
while (funcBodyStart <= posEnd)
1886+
funcBodyStart++;
1887+
return GetOrSetPointOfInsertion(funcBodyStart, posEnd, ln, sci);
1888+
}
1889+
1890+
return funcBodyStart + 1;
1891+
}
1892+
1893+
/// <summary>
1894+
/// Tries to get the best position after a statement, to add new code, inserting new lines if needed.
1895+
/// </summary>
1896+
/// <param name="startPos">The position inside the Scintilla document where the statement starts</param>
1897+
/// <param name="endPos">The position inside the Scintilla document where the owner member of the statement ends</param>
1898+
/// <param name="sci">The Scintilla control containing the document</param>
1899+
/// <returns>The position inside the Scintilla document</returns>
1900+
/// <remarks>For now internal because for the current use we don't need to detect a lot of cases! use with caution!</remarks>
1901+
internal static int GetEndOfStatement(int startPos, int endPos, ScintillaControl sci)
1902+
{
1903+
int groupCount = 0;
1904+
int brCount = 0;
1905+
int statementEnd = startPos;
1906+
while (statementEnd < endPos)
18801907
{
1881-
char c = (char)Sci.CharAt(++funcBodyStart);
1908+
char c = (char)sci.CharAt(statementEnd++);
1909+
1910+
bool endOfStatement = false;
1911+
switch (c)
1912+
{
1913+
case '\r':
1914+
case '\n':
1915+
endOfStatement = groupCount == 0 && brCount == 0;
1916+
break;
1917+
case ';':
1918+
endOfStatement = brCount == 0; // valid or invalid end of statement
1919+
break;
1920+
case '(':
1921+
case '[':
1922+
groupCount++;
1923+
break;
1924+
case '{':
1925+
brCount++;
1926+
break;
1927+
case ')':
1928+
case ']':
1929+
groupCount--;
1930+
break;
1931+
case '}':
1932+
brCount--;
1933+
break;
1934+
}
1935+
1936+
if (endOfStatement) break;
1937+
}
1938+
1939+
return statementEnd;
1940+
}
1941+
1942+
/// <summary>
1943+
/// Looks for the best next position to insert new code, inserting new lines if needed
1944+
/// </summary>
1945+
/// <param name="startPos">The position inside the Scintilla document to start looking for the insertion position</param>
1946+
/// <param name="endPos">The end position inside the Scintilla document</param>
1947+
/// <param name="baseLine">The line inside the document to use as the base for the indentation level and detect if the desired point
1948+
/// matches the end line</param>
1949+
/// <param name="sci">The ScintillaControl where our document resides</param>
1950+
/// <returns>The insertion point position</returns>
1951+
private static int GetOrSetPointOfInsertion(int startPos, int endPos, int baseLine, ScintillaControl sci)
1952+
{
1953+
char[] characterClass = { ' ', '\r', '\n', '\t' };
1954+
int nCount = 0;
1955+
int extraLine = 1;
1956+
1957+
int initialLn = sci.LineFromPosition(startPos);
1958+
int baseIndent = sci.GetLineIndentation(baseLine);
1959+
1960+
bool found = false;
1961+
while (startPos <= endPos)
1962+
{
1963+
char c = (char)sci.CharAt(startPos);
18821964
if (Array.IndexOf(characterClass, c) == -1)
18831965
{
1884-
int endLn = Sci.LineFromPosition(funcBodyStart);
1885-
if (endLn == ln)
1966+
int endLn = sci.LineFromPosition(startPos);
1967+
if (endLn == baseLine || endLn == initialLn)
18861968
{
1887-
Sci.InsertText(funcBodyStart, Sci.NewLineMarker);
1969+
sci.InsertText(startPos, sci.NewLineMarker);
18881970
// Do we want to set the line indentation no matter what? {\r\t\t\t\r} -> {\r\t\r}
18891971
// Better results in most cases, but maybe highly unwanted in others?
1890-
Sci.SetLineIndentation(++endLn, indent + Sci.Indent);
1891-
funcBodyStart = Sci.LineIndentPosition(endLn);
1972+
sci.SetLineIndentation(++endLn, baseIndent + sci.Indent);
1973+
startPos = sci.LineIndentPosition(endLn);
18921974
}
18931975
if (c == '}')
18941976
{
1895-
Sci.InsertText(funcBodyStart, Sci.NewLineMarker);
1896-
Sci.SetLineIndentation(endLn + 1, indent);
1977+
sci.InsertText(startPos, sci.NewLineMarker);
1978+
sci.SetLineIndentation(endLn + 1, baseIndent);
1979+
// In relation with previous comment... we'll reinden this one: {\r} -> {\r\t\r}
1980+
if (sci.GetLineIndentation(endLn) <= baseIndent)
1981+
{
1982+
sci.SetLineIndentation(endLn, baseIndent + sci.Indent);
1983+
startPos = sci.LineIndentPosition(endLn);
1984+
}
18971985
}
1986+
found = true;
18981987
break;
18991988
}
1900-
else if (Sci.EOLMode == 1 && c == '\r' && (++nCount) > extraLine)
1989+
else if (sci.EOLMode == 1 && c == '\r' && (++nCount) > extraLine)
19011990
{
1991+
found = true;
19021992
break;
19031993
}
19041994
else if (c == '\n' && (++nCount) > extraLine)
19051995
{
1906-
if (Sci.EOLMode != 2)
1996+
if (sci.EOLMode != 2)
19071997
{
1908-
funcBodyStart--;
1998+
startPos--;
19091999
}
2000+
found = true;
19102001
break;
19112002
}
1912-
}
1913-
return funcBodyStart;
2003+
startPos++;
2004+
}
2005+
2006+
if (!found) startPos--;
2007+
2008+
return startPos;
19142009
}
19152010

19162011
private static void GenerateToString(ClassModel inClass, ScintillaControl sci, MemberModel member)

Tests/External/Plugins/ASCompletion.Tests/ASCompletion.Tests.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@
155155
<EmbeddedResource Include="Test Files\generated\haxe\ImplementInterfaceNoMembersInsertSingleProperty.hx" />
156156
<EmbeddedResource Include="Test Files\parser\haxe\NotGenericTest.hx" />
157157
<EmbeddedResource Include="Test Files\parser\as3\CompletionErrorTest.as" />
158+
<EmbeddedResource Include="Test Files\generated\as3\FieldFromParameterEmptyBody.as" />
159+
<EmbeddedResource Include="Test Files\generated\as3\FieldFromParameterWithBody.as" />
160+
<EmbeddedResource Include="Test Files\generated\as3\FieldFromParameterWithOtherVars.as" />
161+
<EmbeddedResource Include="Test Files\generated\as3\FieldFromParameterWithSuperConstructor.as" />
162+
<EmbeddedResource Include="Test Files\generated\as3\FieldFromParameterWithSuperConstructorMultiLine.as" />
163+
<EmbeddedResource Include="Test Files\generated\as3\FieldFromParameterWithWrongSuperConstructor.as" />
164+
<EmbeddedResource Include="Test Files\generated\as3\BeforeFieldFromParameterWithSuperConstructorMultiLine.as" />
165+
<EmbeddedResource Include="Test Files\generated\as3\BeforeFieldFromParameterWithWrongSuperConstructor.as" />
158166
</ItemGroup>
159167
<ItemGroup>
160168
<ProjectReference Include="..\..\..\..\External\Plugins\AS2Context\AS2Context.csproj">

0 commit comments

Comments
 (0)