Browse Source

Implemented C# cref parser.

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
b65637108b
  1. 100
      ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs
  2. 5
      ICSharpCode.NRefactory.CSharp/Parser/mcs/doc.cs
  3. 114
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  4. 19
      ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpDocumentationComment.cs
  5. 21
      ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs
  6. 20
      ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs

100
ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs

@ -3469,6 +3469,73 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3469,6 +3469,73 @@ namespace ICSharpCode.NRefactory.CSharp
return result;
}
#endregion
#region XmlDoc
public DocumentationReference ConvertXmlDoc(DocumentationBuilder doc)
{
DocumentationReference result = new DocumentationReference();
if (doc.ParsedName != null) {
if (doc.ParsedName.Name == "<this>") {
result.EntityType = EntityType.Indexer;
} else {
result.MemberName = doc.ParsedName.Name;
}
if (doc.ParsedName.Left != null) {
result.DeclaringType = ConvertToType(doc.ParsedName.Left);
} else if (doc.ParsedBuiltinType != null) {
result.DeclaringType = ConvertToType(doc.ParsedBuiltinType);
}
if (doc.ParsedName.TypeParameters != null) {
for (int i = 0; i < doc.ParsedName.TypeParameters.Count; i++) {
result.TypeArguments.Add(ConvertToType(doc.ParsedName.TypeParameters[i]));
}
}
} else if (doc.ParsedBuiltinType != null) {
result.EntityType = EntityType.TypeDefinition;
result.DeclaringType = ConvertToType(doc.ParsedBuiltinType);
}
if (doc.ParsedParameters != null) {
result.HasParameterList = true;
result.Parameters.AddRange(doc.ParsedParameters.Select(ConvertXmlDocParameter));
}
if (doc.ParsedOperator != null) {
result.EntityType = EntityType.Operator;
result.OperatorType = (OperatorType)doc.ParsedOperator;
if (result.OperatorType == OperatorType.Implicit || result.OperatorType == OperatorType.Explicit) {
var returnTypeParam = result.Parameters.LastOrNullObject();
returnTypeParam.Remove(); // detach from parameter list
var returnType = returnTypeParam.Type;
returnType.Remove();
result.ConversionOperatorReturnType = returnType;
}
if (result.Parameters.Count == 0) {
// reset HasParameterList if necessary
result.HasParameterList = false;
}
}
return result;
}
ParameterDeclaration ConvertXmlDocParameter(DocumentationParameter p)
{
ParameterDeclaration result = new ParameterDeclaration();
switch (p.Modifier) {
case Parameter.Modifier.OUT:
result.ParameterModifier = ParameterModifier.Out;
break;
case Parameter.Modifier.REF:
result.ParameterModifier = ParameterModifier.Ref;
break;
case Parameter.Modifier.PARAMS:
result.ParameterModifier = ParameterModifier.Params;
break;
}
if (p.Type != null) {
result.Type = ConvertToType(p.Type);
}
return result;
}
#endregion
}
public CSharpParser ()
@ -3796,12 +3863,39 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3796,12 +3863,39 @@ namespace ICSharpCode.NRefactory.CSharp
public DocumentationReference ParseDocumentationReference (string cref)
{
// see Mono.CSharp.DocumentationBuilder.HandleXrefCommon
if (cref == null)
throw new ArgumentNullException ("cref");
// Additional symbols for < and > are allowed for easier XML typing
cref = cref.Replace ('{', '<').Replace ('}', '>');
// TODO: add support for parsing cref attributes
// (documentation_parsing production, see DocumentationBuilder.HandleXrefCommon)
throw new NotImplementedException ();
lock (parseLock) {
errorReportPrinter = new ErrorReportPrinter("");
var ctx = new CompilerContext(compilerSettings.ToMono(), errorReportPrinter);
ctx.Settings.TabSize = 1;
var stream = new MemoryStream(Encoding.Unicode.GetBytes(cref));
var reader = new SeekableStreamReader(stream, Encoding.Unicode);
var file = new SourceFile("", "", 0);
Location.Initialize(new List<SourceFile> (new [] { file }));
var module = new ModuleContainer(ctx);
module.DocumentationBuilder = new DocumentationBuilder();
var source_file = new CompilationSourceFile (module);
var report = new Report (ctx, errorReportPrinter);
var parser = new Mono.CSharp.CSharpParser (reader, source_file, report);
parser.Lexer.putback_char = Tokenizer.DocumentationXref;
parser.Lexer.parsing_generic_declaration_doc = true;
parser.parse ();
if (report.Errors > 0) {
// Report.Warning (1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'",
// mc.GetSignatureForError (), cref);
}
ConversionVisitor conversionVisitor = new ConversionVisitor (false, parser.LocationsBag);
DocumentationReference docRef = conversionVisitor.ConvertXmlDoc(module.DocumentationBuilder);
CompilerCallableEntryPoint.Reset();
return docRef;
}
}
}
}

5
ICSharpCode.NRefactory.CSharp/Parser/mcs/doc.cs

@ -56,6 +56,11 @@ namespace Mono.CSharp @@ -56,6 +56,11 @@ namespace Mono.CSharp
XmlDocumentation = new XmlDocument ();
XmlDocumentation.PreserveWhitespace = false;
}
internal DocumentationBuilder()
{
// for NRefactory CSharpParser.ParseDocumentationReference
}
Report Report {
get {

114
ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs

@ -938,6 +938,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -938,6 +938,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ScanChildren(parameterDeclaration);
if (resolverEnabled) {
string name = parameterDeclaration.Name;
if (parameterDeclaration.Parent is DocumentationReference) {
// create a dummy parameter
IType type = ResolveType(parameterDeclaration.Type);
switch (parameterDeclaration.ParameterModifier) {
case ParameterModifier.Ref:
case ParameterModifier.Out:
type = new ByReferenceType(type);
break;
}
return new LocalResolveResult(new DefaultParameter(
type, name,
isRef: parameterDeclaration.ParameterModifier == ParameterModifier.Ref,
isOut: parameterDeclaration.ParameterModifier == ParameterModifier.Out,
isParams: parameterDeclaration.ParameterModifier == ParameterModifier.Params));
}
// Look in lambda parameters:
foreach (IParameter p in resolver.LocalVariables.OfType<IParameter>()) {
if (p.Name == name)
@ -3855,7 +3872,102 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -3855,7 +3872,102 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Documentation Reference
ResolveResult IAstVisitor<ResolveResult>.VisitDocumentationReference(DocumentationReference documentationReference)
{
throw new NotImplementedException();
// Resolve child nodes:
ITypeDefinition declaringTypeDef;
if (documentationReference.DeclaringType.IsNull)
declaringTypeDef = resolver.CurrentTypeDefinition;
else
declaringTypeDef = ResolveType(documentationReference.DeclaringType).GetDefinition();
IType[] typeArguments = documentationReference.TypeArguments.Select(ResolveType).ToArray();
IType conversionOperatorReturnType = ResolveType(documentationReference.ConversionOperatorReturnType);
IParameter[] parameters = documentationReference.Parameters.Select(ResolveXmlDocParameter).ToArray();
if (documentationReference.EntityType == EntityType.TypeDefinition) {
if (declaringTypeDef != null)
return new TypeResolveResult(declaringTypeDef);
else
return errorResult;
}
if (documentationReference.EntityType == EntityType.None) {
// might be a type, member or ctor
string memberName = documentationReference.MemberName;
ResolveResult rr;
if (documentationReference.DeclaringType.IsNull) {
rr = resolver.LookupSimpleNameOrTypeName(memberName, typeArguments, NameLookupMode.Expression);
} else {
var target = Resolve(documentationReference.DeclaringType);
rr = resolver.ResolveMemberAccess(target, memberName, typeArguments);
}
// reduce to definition:
if (rr.IsError) {
return rr;
} else if (rr is TypeResolveResult) {
var typeDef = rr.Type.GetDefinition();
if (typeDef == null)
return errorResult;
if (documentationReference.HasParameterList) {
var ctors = typeDef.GetConstructors(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions);
return FindByParameters(ctors, parameters);
} else {
return new TypeResolveResult(typeDef);
}
} else if (rr is MemberResolveResult) {
var mrr = (MemberResolveResult)rr;
return new MemberResolveResult(null, mrr.Member.MemberDefinition);
} else if (rr is MethodGroupResolveResult) {
var mgrr = (MethodGroupResolveResult)rr;
var methods = mgrr.MethodsGroupedByDeclaringType.Reverse()
.SelectMany(ml => ml.Select(m => (IParameterizedMember)m.MemberDefinition));
return FindByParameters(methods, parameters);
}
return rr;
}
// Indexer or operator
if (declaringTypeDef == null)
return errorResult;
if (documentationReference.EntityType == EntityType.Indexer) {
var indexers = declaringTypeDef.Properties.Where(p => p.IsIndexer && !p.IsExplicitInterfaceImplementation);
return FindByParameters(indexers, parameters);
} else if (documentationReference.EntityType == EntityType.Operator) {
var opType = documentationReference.OperatorType;
string memberName = OperatorDeclaration.GetName(opType);
var methods = declaringTypeDef.Methods.Where(m => m.IsOperator && m.Name == memberName);
if (opType == OperatorType.Implicit || opType == OperatorType.Explicit) {
// conversion operator
foreach (var method in methods) {
if (ParameterListComparer.Instance.Equals(method.Parameters, parameters)) {
if (method.ReturnType.Equals(conversionOperatorReturnType))
return new MemberResolveResult(null, method);
}
}
return new MemberResolveResult(null, methods.FirstOrDefault());
} else {
// not a conversion operator
return FindByParameters(methods, parameters);
}
} else {
throw new NotSupportedException(); // unknown entity type
}
}
IParameter ResolveXmlDocParameter(ParameterDeclaration p)
{
var lrr = Resolve(p) as LocalResolveResult;
if (lrr != null && lrr.IsParameter)
return (IParameter)lrr.Variable;
else
return new DefaultParameter(SpecialType.UnknownType, string.Empty);
}
ResolveResult FindByParameters(IEnumerable<IParameterizedMember> methods, IList<IParameter> parameters)
{
foreach (var method in methods) {
if (ParameterListComparer.Instance.Equals(method.Parameters, parameters))
return new MemberResolveResult(null, method);
}
return new MemberResolveResult(null, methods.FirstOrDefault());
}
#endregion
}

19
ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpDocumentationComment.cs

@ -17,8 +17,10 @@ @@ -17,8 +17,10 @@
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.TypeSystem
@ -38,6 +40,23 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -38,6 +40,23 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
// resolve ID string
return base.ResolveCref(cref);
}
var documentationReference = new CSharpParser().ParseDocumentationReference(cref);
var csharpContext = context as CSharpTypeResolveContext;
CSharpResolver resolver;
if (csharpContext != null) {
resolver = new CSharpResolver(csharpContext);
} else {
resolver = new CSharpResolver(context.Compilation);
}
var astResolver = new CSharpAstResolver(resolver, documentationReference);
var rr = astResolver.Resolve(documentationReference);
MemberResolveResult mrr = rr as MemberResolveResult;
if (mrr != null)
return mrr.Member;
TypeResolveResult trr = rr as TypeResolveResult;
if (trr != null)
return trr.Type.GetDefinition();
return null;
}
}

21
ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs

@ -26,7 +26,6 @@ using NUnit.Framework; @@ -26,7 +26,6 @@ using NUnit.Framework;
namespace ICSharpCode.NRefactory.Documentation
{
[TestFixture]
[Ignore("Cref parsing not yet implemented")]
public class CSharpCrefLookupTests
{
IEntity Lookup(string cref)
@ -58,7 +57,7 @@ class Impl<T> : IGeneric<List<string>[,], T> { @@ -58,7 +57,7 @@ class Impl<T> : IGeneric<List<string>[,], T> {
var pc = new CSharpProjectContent().AddAssemblyReferences(new[] { CecilLoaderTests.Mscorlib });
var cu = new CSharpParser().Parse(new StringReader(program), "program.cs");
var compilation = pc.UpdateProjectContent(null, cu.ToTypeSystem()).CreateCompilation();
var typeDefinition = compilation.MainAssembly.TopLevelTypeDefinitions.Single();
var typeDefinition = compilation.MainAssembly.TopLevelTypeDefinitions.First();
IEntity entity = typeDefinition.Documentation.ResolveCref(cref);
Assert.IsNotNull(entity, "ResolveCref() returned null.");
return entity;
@ -109,7 +108,7 @@ class Impl<T> : IGeneric<List<string>[,], T> { @@ -109,7 +108,7 @@ class Impl<T> : IGeneric<List<string>[,], T> {
[Test]
public void M()
{
Assert.AreEqual("M:Test.M(System.String[0:,0:])",
Assert.AreEqual("M:Test.M(System.Int32)",
IdStringProvider.GetIdString(Lookup("M")));
}
@ -141,19 +140,25 @@ class Impl<T> : IGeneric<List<string>[,], T> { @@ -141,19 +140,25 @@ class Impl<T> : IGeneric<List<string>[,], T> {
[Test]
public void MethodInGenericInterface()
{
Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)",
Assert.AreEqual("M:IGeneric`2.Test``1(``0[0:,0:]@)",
IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test")));
Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)",
Assert.AreEqual("M:IGeneric`2.Test``1(``0[0:,0:]@)",
IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test{Z}")));
Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)",
Assert.AreEqual("M:IGeneric`2.Test``1(``0[0:,0:]@)",
IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test{Z}(ref Z[,])")));
}
[Test]
public void Indexer()
[Ignore("Fails due to mcs parser bug (see CSharpCrefParserTests.This)")]
public void IndexerWithoutDeclaringType()
{
Assert.AreEqual("P:Test.Item(System.Int32)",
IdStringProvider.GetIdString(Lookup("this")));
}
[Test]
public void IndexerWithDeclaringType()
{
Assert.AreEqual("P:Test.Item(System.Int32)",
IdStringProvider.GetIdString(Lookup("Test.this")));
Assert.AreEqual("P:Test.Item(System.Int32)",
@ -161,6 +166,7 @@ class Impl<T> : IGeneric<List<string>[,], T> { @@ -161,6 +166,7 @@ class Impl<T> : IGeneric<List<string>[,], T> {
}
[Test]
[Ignore("mcs bug, see CSharpCrefParserTests.OperatorPlusWithDeclaringType")]
public void OperatorPlus()
{
Assert.AreEqual("M:Test.op_Addition(Test,System.Int32)",
@ -172,6 +178,7 @@ class Impl<T> : IGeneric<List<string>[,], T> { @@ -172,6 +178,7 @@ class Impl<T> : IGeneric<List<string>[,], T> {
}
[Test]
[Ignore("mcs bug, see CSharpCrefParserTests.OperatorPlusWithDeclaringType")]
public void ImplicitOperator()
{
Assert.AreEqual("M:Test.op_Implicit(Test)~System.Int32",

20
ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs

@ -25,7 +25,6 @@ using NUnit.Framework; @@ -25,7 +25,6 @@ using NUnit.Framework;
namespace ICSharpCode.NRefactory.Documentation
{
[TestFixture]
[Ignore("Cref parsing not yet implemented")]
public class CSharpCrefParserTests
{
[Test]
@ -39,6 +38,7 @@ namespace ICSharpCode.NRefactory.Documentation @@ -39,6 +38,7 @@ namespace ICSharpCode.NRefactory.Documentation
}
[Test]
[Ignore("mcs bug")]
public void This()
{
ParseUtilCSharp.AssertDocumentationReference(
@ -49,6 +49,7 @@ namespace ICSharpCode.NRefactory.Documentation @@ -49,6 +49,7 @@ namespace ICSharpCode.NRefactory.Documentation
}
[Test]
[Ignore("mcs bug (Unexpected symbol `this', expecting `explicit', `implicit', `operator', or `type')")]
public void ThisWithParameter()
{
ParseUtilCSharp.AssertDocumentationReference(
@ -115,6 +116,21 @@ namespace ICSharpCode.NRefactory.Documentation @@ -115,6 +116,21 @@ namespace ICSharpCode.NRefactory.Documentation
});
}
[Test]
public void IntParse()
{
ParseUtilCSharp.AssertDocumentationReference(
"int.Parse(string)",
new DocumentationReference {
DeclaringType = new PrimitiveType("int"),
MemberName = "Parse",
HasParameterList = true,
Parameters = {
new ParameterDeclaration { Type = new PrimitiveType("string") }
}
});
}
[Test]
public void Generic()
{
@ -201,6 +217,7 @@ namespace ICSharpCode.NRefactory.Documentation @@ -201,6 +217,7 @@ namespace ICSharpCode.NRefactory.Documentation
}
[Test]
[Ignore("mcs bug (Unexpected symbol `operator', expecting `identifier' or `this')")]
public void OperatorPlusWithDeclaringType()
{
ParseUtilCSharp.AssertDocumentationReference(
@ -256,6 +273,7 @@ namespace ICSharpCode.NRefactory.Documentation @@ -256,6 +273,7 @@ namespace ICSharpCode.NRefactory.Documentation
}
[Test]
[Ignore("mcs bug (Unexpected symbol `explicit', expecting `identifier' or `this')")]
public void ExplicitOperatorWithParameterListAndDeclaringType()
{
ParseUtilCSharp.AssertDocumentationReference(

Loading…
Cancel
Save