Browse Source

Fixed C# ExpressionFinder to support generics.

Implemented field references on generic classes in c# parser ('SomeGenericClass<string>.StaticProperty = "Beispiel";')
Fixed form designer code generic (use "this" instead of class name).

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@157 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 21 years ago
parent
commit
973804ccb4
  1. 81
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/ExpressionFinder.cs
  2. 19
      src/AddIns/DisplayBindings/FormDesigner/Project/Src/FormDesigner/DesignerGenerator/CodeDOMGenerator.cs
  3. 1962
      src/Libraries/NRefactory/Project/Src/Parser/CSharp/Parser.cs
  4. 37
      src/Libraries/NRefactory/Project/Src/Parser/CSharp/cs.ATG
  5. 2
      src/Libraries/NRefactory/Project/Src/Parser/Visitors/AbstractASTVisitor.cs
  6. 10
      src/Libraries/NRefactory/Project/Src/Parser/Visitors/LookupTableVisitor.cs
  7. 12
      src/Libraries/NRefactory/Test/Parser/Expressions/FieldReferenceExpressionTests.cs
  8. 27
      src/Main/Base/Test/GenericResolverTests.cs
  9. 47
      src/Main/Base/Test/NRefactoryResolverTests.cs

81
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/ExpressionFinder.cs

@ -57,6 +57,13 @@ namespace CSharpBinding.Parser @@ -57,6 +57,13 @@ namespace CSharpBinding.Parser
break;
b.Append(inText, i, otherBracket - i + 1);
break;
} else if (c == '<') {
// accept only if this is a generic type reference
int typeParameterEnd = FindEndOfTypeParameters(inText, i);
if (typeParameterEnd < 0)
break;
b.Append(inText, i, typeParameterEnd - i + 1);
i = typeParameterEnd;
} else {
break;
}
@ -64,6 +71,30 @@ namespace CSharpBinding.Parser @@ -64,6 +71,30 @@ namespace CSharpBinding.Parser
return b.ToString();
}
int FindEndOfTypeParameters(string inText, int offset)
{
int level = 0;
for (int i = offset; i < inText.Length; ++i) {
char c = inText[i];
if (Char.IsLetterOrDigit(c) || Char.IsWhiteSpace(c)) {
// ignore identifiers and whitespace
} else if (c == ',' || c == '?' || c == '[' || c == ']') {
// , : seperating generic type parameters
// ? : nullable types
// [] : arrays
} else if (c == '<') {
++level;
} else if (c == '>') {
--level;
} else {
return -1;
}
if (level == 0)
return i;
}
return -1;
}
#region SearchBracketForward
// like CSharpFormattingStrategy.SearchBracketForward, but operates on a string.
private int SearchBracketForward(string text, int offset, char openBracket, char closingBracket)
@ -346,15 +377,16 @@ namespace CSharpBinding.Parser @@ -346,15 +377,16 @@ namespace CSharpBinding.Parser
void ReadNextToken()
{
char ch = GetNext();
char ch;
curTokenType = Err;
if (ch == '\0') {
return;
}
while (Char.IsWhiteSpace(ch)) {
do {
ch = GetNext();
}
if (ch == '\0') {
return;
}
} while (Char.IsWhiteSpace(ch));
switch (ch) {
case '}':
@ -372,6 +404,12 @@ namespace CSharpBinding.Parser @@ -372,6 +404,12 @@ namespace CSharpBinding.Parser
curTokenType = Bracket;
}
break;
case '>':
if (ReadTypeParameters()) {
// hack: ignore type parameters and continue reading without changing state
ReadNextToken();
}
break;
case '.':
curTokenType = Dot;
break;
@ -433,6 +471,32 @@ namespace CSharpBinding.Parser @@ -433,6 +471,32 @@ namespace CSharpBinding.Parser
}
}
bool ReadTypeParameters()
{
int level = 1;
while (level > 0) {
char ch = GetNext();
switch (ch) {
case '?':
case '[':
case ',':
case ']':
break;
case '<':
--level;
break;
case '>':
++level;
break;
default:
if (!char.IsWhiteSpace(ch) && !char.IsLetterOrDigit(ch))
return false;
break;
}
}
return true;
}
bool ReadBracket(char openBracket, char closingBracket)
{
int curlyBraceLevel = 0;
@ -452,10 +516,9 @@ namespace CSharpBinding.Parser @@ -452,10 +516,9 @@ namespace CSharpBinding.Parser
while (parenthesisLevel != 0 || squareBracketLevel != 0 || curlyBraceLevel != 0) {
char ch = GetNext();
if (ch == '\0') {
return false;
}
switch (ch) {
case '\0':
return false;
case '(':
parenthesisLevel--;
break;

19
src/AddIns/DisplayBindings/FormDesigner/Project/Src/FormDesigner/DesignerGenerator/CodeDOMGenerator.cs

@ -47,30 +47,35 @@ namespace ICSharpCode.FormDesigner @@ -47,30 +47,35 @@ namespace ICSharpCode.FormDesigner
public void ConvertContentDefinition(TextWriter writer)
{
DesignerSerializationManager serializationManager = (DesignerSerializationManager )host.GetService(typeof(IDesignerSerializationManager));
DesignerSerializationManager serializationManager = (DesignerSerializationManager)host.GetService(typeof(IDesignerSerializationManager));
IDisposable session = serializationManager.CreateSession();
DesignerResourceService designerResourceService = (DesignerResourceService)host.GetService(typeof(System.ComponentModel.Design.IResourceService));
designerResourceService.SerializationStarted(true);
CodeDomSerializer rootSerializer = (CodeDomSerializer)serializationManager.GetSerializer(host.RootComponent.GetType(), typeof(CodeDomSerializer));
Type componentType = host.RootComponent.GetType();
ExpressionContext exprContext = new ExpressionContext(new CodeThisReferenceExpression(), componentType, host.RootComponent, host.RootComponent);
((IDesignerSerializationManager)serializationManager).Context.Append(exprContext);
CodeDomSerializer rootSerializer = (CodeDomSerializer)serializationManager.GetSerializer(componentType, typeof(CodeDomSerializer));
if (rootSerializer == null) {
throw new Exception("No root serializer found");
}
ICollection statements = rootSerializer.Serialize(serializationManager, host.RootComponent) as ICollection;
codeDOMGeneratorUtility.CreateCodeGeneratorOptions.IndentString = "\t\t";
CodeGeneratorOptions options = codeDOMGeneratorUtility.CreateCodeGeneratorOptions;
options.IndentString = "\t\t\t";
foreach (CodeStatement statement in statements) {
if (!(statement is CodeVariableDeclarationStatement)) {
// indentation isn't generated when calling GenerateCodeFromStatement
writer.Write(options.IndentString);
try {
codeProvider.GenerateCodeFromStatement(statement,
writer,
codeDOMGeneratorUtility.CreateCodeGeneratorOptions);
codeProvider.GenerateCodeFromStatement(statement, writer, options);
} catch (Exception e) {
codeProvider.GenerateCodeFromStatement(new CodeCommentStatement("TODO: Error while generating statement : " + e.Message),
writer,
codeDOMGeneratorUtility.CreateCodeGeneratorOptions);
options);
}
}
}

1962
src/Libraries/NRefactory/Project/Src/Parser/CSharp/Parser.cs

File diff suppressed because it is too large Load Diff

37
src/Libraries/NRefactory/Project/Src/Parser/CSharp/cs.ATG

@ -372,6 +372,37 @@ bool IsShiftRight() @@ -372,6 +372,37 @@ bool IsShiftRight()
return (la.kind == Tokens.GreaterThan && next.kind == Tokens.GreaterThan);
}
bool IsTypeReferenceExpression(Expression expr)
{
if (expr is TypeReferenceExpression) return ((TypeReferenceExpression)expr).TypeReference.GenericTypes.Count == 0;
while (expr is FieldReferenceExpression) {
expr = ((FieldReferenceExpression)expr).TargetObject;
}
return expr is IdentifierExpression;
}
TypeReferenceExpression GetTypeReferenceExpression(Expression expr, List<TypeReference> genericTypes)
{
TypeReferenceExpression tre = expr as TypeReferenceExpression;
if (tre != null) {
return new TypeReferenceExpression(new TypeReference(tre.TypeReference.Type, tre.TypeReference.PointerNestingLevel, tre.TypeReference.RankSpecifier, genericTypes));
}
StringBuilder b = new StringBuilder();
WriteFullTypeName(b, expr);
return new TypeReferenceExpression(new TypeReference(b.ToString(), 0, null, genericTypes));
}
void WriteFullTypeName(StringBuilder b, Expression expr)
{
FieldReferenceExpression fre = expr as FieldReferenceExpression;
if (fre != null) {
WriteFullTypeName(b, fre.TargetObject);
b.Append('.');
b.Append(fre.FieldName);
} else if (expr is IdentifierExpression) {
b.Append(((IdentifierExpression)expr).Identifier);
}
}
/*------------------------------------------------------------------------*
*----- LEXER TOKEN LIST ------------------------------------------------*
@ -1981,6 +2012,10 @@ PrimaryExpr<out Expression pexpr> @@ -1981,6 +2012,10 @@ PrimaryExpr<out Expression pexpr>
/*--- member access */
| "->" ident (. pexpr = new PointerReferenceExpression(pexpr, t.val); .)
| "." ident (. pexpr = new FieldReferenceExpression(pexpr, t.val);.)
/* member access on generic type */
| ( IF (IsGenericFollowedBy(Tokens.Dot) && IsTypeReferenceExpression(pexpr))
TypeArgumentList<out typeList> )
"." ident (. pexpr = new FieldReferenceExpression(GetTypeReferenceExpression(pexpr, typeList), t.val);.)
/*--- invocation expression: */
| "(" (. ArrayList parameters = new ArrayList(); .)
[ Argument<out expr> (. if (expr != null) {parameters.Add(expr);} .)
@ -2004,6 +2039,7 @@ PrimaryExpr<out Expression pexpr> @@ -2004,6 +2039,7 @@ PrimaryExpr<out Expression pexpr>
AnonymousMethodExpr<out Expression outExpr>
(.
AnonymousMethodExpression expr = new AnonymousMethodExpression();
expr.StartLocation = t.Location;
Statement stmt;
ArrayList p;
outExpr = expr;
@ -2021,6 +2057,7 @@ AnonymousMethodExpr<out Expression outExpr> @@ -2021,6 +2057,7 @@ AnonymousMethodExpr<out Expression outExpr>
(. lexer.SkipCurrentBlock(); .)
"}"
(. } .)
(. expr.EndLocation = t.Location; .)
.
ConditionalOrExpr<ref Expression outExpr>

2
src/Libraries/NRefactory/Project/Src/Parser/Visitors/AbstractASTVisitor.cs

@ -1023,7 +1023,7 @@ namespace ICSharpCode.NRefactory.Parser @@ -1023,7 +1023,7 @@ namespace ICSharpCode.NRefactory.Parser
return data;
}
public object Visit(AnonymousMethodExpression anonymousMethodExpression, object data)
public virtual object Visit(AnonymousMethodExpression anonymousMethodExpression, object data)
{
Debug.Assert(anonymousMethodExpression != null);
Debug.Assert(anonymousMethodExpression.Parameters != null);

10
src/Libraries/NRefactory/Project/Src/Parser/Visitors/LookupTableVisitor.cs

@ -103,6 +103,14 @@ namespace ICSharpCode.NRefactory.Parser @@ -103,6 +103,14 @@ namespace ICSharpCode.NRefactory.Parser
return data;
}
public override object Visit(AnonymousMethodExpression anonymousMethodExpression, object data)
{
foreach (ParameterDeclarationExpression p in anonymousMethodExpression.Parameters) {
AddVariable(p.TypeReference, p.ParameterName, anonymousMethodExpression.StartLocation, anonymousMethodExpression.EndLocation);
}
return base.Visit(anonymousMethodExpression, data);
}
// ForStatement and UsingStatement use a LocalVariableDeclaration,
// so they don't need to be visited separately
@ -122,6 +130,8 @@ namespace ICSharpCode.NRefactory.Parser @@ -122,6 +130,8 @@ namespace ICSharpCode.NRefactory.Parser
return foreachStatement.EmbeddedStatement.AcceptVisitor(this, data);
}
public override object Visit(TryCatchStatement tryCatchStatement, object data)
{
if (tryCatchStatement == null) {

12
src/Libraries/NRefactory/Test/Parser/Expressions/FieldReferenceExpressionTests.cs

@ -39,6 +39,18 @@ namespace ICSharpCode.NRefactory.Tests.AST @@ -39,6 +39,18 @@ namespace ICSharpCode.NRefactory.Tests.AST
Assert.AreEqual(1, tr.GenericTypes.Count);
Assert.AreEqual("System.String", tr.GenericTypes[0].SystemType);
}
[Test]
public void CSharpFullNamespaceGenericFieldReferenceExpressionTest()
{
FieldReferenceExpression fre = (FieldReferenceExpression)ParseUtilCSharp.ParseExpression("Namespace.Subnamespace.SomeClass<string>.myField", typeof(FieldReferenceExpression));
Assert.AreEqual("myField", fre.FieldName);
Assert.IsTrue(fre.TargetObject is TypeReferenceExpression);
TypeReference tr = ((TypeReferenceExpression)fre.TargetObject).TypeReference;
Assert.AreEqual("Namespace.Subnamespace.SomeClass", tr.Type);
Assert.AreEqual(1, tr.GenericTypes.Count);
Assert.AreEqual("System.String", tr.GenericTypes[0].SystemType);
}
#endregion
#region VB.NET

27
src/Main/Base/Test/GenericResolverTests.cs

@ -31,6 +31,11 @@ class TestClass { @@ -31,6 +31,11 @@ class TestClass {
List<TestClass> list = new List<TestClass>();
}
T CloneIt<T>(T source) where T : ICloneable {
return source.Clone();
}
}
";
@ -68,5 +73,27 @@ class TestClass { @@ -68,5 +73,27 @@ class TestClass {
Assert.AreEqual("TestClass", m.ReturnType.FullyQualifiedName);
Assert.AreEqual(1, m.ReturnType.ArrayDimensions);
}
[Test]
public void ClassReferenceTest()
{
ResolveResult result = Resolve(listProgram, "List<string>", 5);
Assert.IsNotNull(result);
Assert.IsTrue(result is TypeResolveResult);
Assert.AreEqual("System.Collections.Generic.List", ((TypeResolveResult)result).ResolvedClass.FullyQualifiedName);
Assert.IsTrue(result.ResolvedType is SpecificReturnType);
Assert.AreEqual("System.String", ((SpecificReturnType)result.ResolvedType).TypeParameters[0].FullyQualifiedName);
}
[Test]
public void GenericMethodCallTest()
{
ResolveResult result = Resolve(listProgram, "CloneIt<TestClass>(null)", 5);
Assert.IsNotNull(result);
Assert.IsTrue(result is MemberResolveResult);
Assert.AreEqual("TestClass", result.ResolvedType.FullyQualifiedName);
MemberResolveResult mrr = (MemberResolveResult) result;
Assert.AreEqual("TestClass.CloneIt", mrr.ResolvedMember.FullyQualifiedName);
}
}
}

47
src/Main/Base/Test/NRefactoryResolverTests.cs

@ -15,6 +15,7 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -15,6 +15,7 @@ namespace ICSharpCode.SharpDevelop.Tests
ICompilationUnit Parse(string fileName, string fileContent)
{
ICSharpCode.NRefactory.Parser.IParser p = ICSharpCode.NRefactory.Parser.ParserFactory.CreateParser(ICSharpCode.NRefactory.Parser.SupportedLanguages.CSharp, new StringReader(fileContent));
p.ParseMethodBodies = false;
p.Parse();
DefaultProjectContent pc = new DefaultProjectContent();
pc.ReferencedContents.Add(corLib);
@ -36,6 +37,7 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -36,6 +37,7 @@ namespace ICSharpCode.SharpDevelop.Tests
ICompilationUnit ParseVB(string fileName, string fileContent)
{
ICSharpCode.NRefactory.Parser.IParser p = ICSharpCode.NRefactory.Parser.ParserFactory.CreateParser(ICSharpCode.NRefactory.Parser.SupportedLanguages.VBNet, new StringReader(fileContent));
p.ParseMethodBodies = false;
p.Parse();
DefaultProjectContent pc = new DefaultProjectContent();
ParserService.ForceProjectContent(pc);
@ -361,6 +363,51 @@ interface IInterface2 { @@ -361,6 +363,51 @@ interface IInterface2 {
Assert.AreEqual(1, m.Parameters.Count, "new A(11.1) parameter count");
Assert.AreEqual("dblVal", m.Parameters[0].Name, "new A(11.1) parameter");
}
[Test]
public void AnonymousMethodParameters()
{
string program = @"class A {
void Method() {
SomeEvent += delegate(object sender, EventArgs e) {
};
} }
";
ResolveResult result = Resolve(program, "e", 4);
Assert.IsNotNull(result);
Assert.IsTrue(result is LocalResolveResult);
Assert.AreEqual("System.EventArgs", result.ResolvedType.FullyQualifiedName);
}
[Test]
public void DefaultTypeCSharp()
{
string program = @"class A {
void Method() {
} }
";
ResolveResult result = Resolve(program, "int", 3);
Assert.IsNotNull(result);
Assert.IsTrue(result is TypeResolveResult);
Assert.AreEqual("System.Int32", result.ResolvedType.FullyQualifiedName);
}
[Test]
public void DefaultTypeVB()
{
string program = @"Class A
Sub Method()
End Sub
End Class
";
ResolveResult result = ResolveVB(program, "inTeGer", 3);
Assert.IsNotNull(result);
Assert.IsTrue(result is TypeResolveResult);
Assert.AreEqual("System.Int32", result.ResolvedType.FullyQualifiedName);
}
#endregion
}
}

Loading…
Cancel
Save